Release 6.1.7
This commit is contained in:
19
ports_module/cortex_r4/iar/example_build/azure_rtos.eww
Normal file
19
ports_module/cortex_r4/iar/example_build/azure_rtos.eww
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<workspace>
|
||||
<project>
|
||||
<path>$WS_DIR$\sample_threadx.ewp</path>
|
||||
</project>
|
||||
<project>
|
||||
<path>$WS_DIR$\sample_threadx_module.ewp</path>
|
||||
</project>
|
||||
<project>
|
||||
<path>$WS_DIR$\sample_threadx_module_manager.ewp</path>
|
||||
</project>
|
||||
<project>
|
||||
<path>$WS_DIR$\tx.ewp</path>
|
||||
</project>
|
||||
<project>
|
||||
<path>$WS_DIR$\txm.ewp</path>
|
||||
</project>
|
||||
<batchBuild />
|
||||
</workspace>
|
||||
177
ports_module/cortex_r4/iar/example_build/cstartup.s
Normal file
177
ports_module/cortex_r4/iar/example_build/cstartup.s
Normal file
@@ -0,0 +1,177 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; Part one of the system initialization code,
|
||||
;; contains low-level
|
||||
;; initialization.
|
||||
;;
|
||||
;; Copyright 2007-2017 IAR Systems AB.
|
||||
;;
|
||||
;; $Revision: 112610 $
|
||||
;;
|
||||
|
||||
MODULE ?cstartup
|
||||
|
||||
;; Forward declaration of sections.
|
||||
SECTION IRQ_STACK:DATA:NOROOT(3)
|
||||
SECTION FIQ_STACK:DATA:NOROOT(3)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
SECTION SVC_STACK:DATA:NOROOT(3)
|
||||
SECTION ABT_STACK:DATA:NOROOT(3)
|
||||
;
|
||||
; The module in this file are included in the libraries, and may be
|
||||
; replaced by any user-defined modules that define the PUBLIC symbol
|
||||
; __iar_program_start or a user defined start symbol.
|
||||
;
|
||||
; To override the cstartup defined in the library, simply add your
|
||||
; modified version to the workbench project.
|
||||
|
||||
SECTION .intvec:CODE:NOROOT(2)
|
||||
|
||||
PUBLIC __vector
|
||||
PUBLIC __iar_program_start
|
||||
EXTERN Undefined_Handler
|
||||
EXTERN SWI_Handler
|
||||
EXTERN Prefetch_Handler
|
||||
EXTERN Abort_Handler
|
||||
EXTERN IRQ_Handler
|
||||
EXTERN FIQ_Handler
|
||||
|
||||
DATA
|
||||
|
||||
__iar_init$$done: ; The vector table is not needed
|
||||
; until after copy initialization is done
|
||||
|
||||
__vector: ; Make this a DATA label, so that stack usage
|
||||
; analysis doesn't consider it an uncalled fun
|
||||
|
||||
ARM
|
||||
|
||||
; All default exception handlers (except reset) are
|
||||
; defined as weak symbol definitions.
|
||||
; If a handler is defined by the application it will take precedence.
|
||||
LDR PC,Reset_Addr ; Reset
|
||||
LDR PC,Undefined_Addr ; Undefined instructions
|
||||
LDR PC,SWI_Addr ; Software interrupt (SWI/SVC)
|
||||
LDR PC,Prefetch_Addr ; Prefetch abort
|
||||
LDR PC,Abort_Addr ; Data abort
|
||||
DCD 0 ; RESERVED
|
||||
LDR PC,IRQ_Addr ; IRQ
|
||||
LDR PC,FIQ_Addr ; FIQ
|
||||
|
||||
DATA
|
||||
|
||||
Reset_Addr: DCD __iar_program_start
|
||||
Undefined_Addr: DCD Undefined_Handler
|
||||
SWI_Addr: DCD SWI_Handler
|
||||
Prefetch_Addr: DCD Prefetch_Handler
|
||||
Abort_Addr: DCD Abort_Handler
|
||||
IRQ_Addr: DCD IRQ_Handler
|
||||
FIQ_Addr: DCD FIQ_Handler
|
||||
|
||||
|
||||
; --------------------------------------------------
|
||||
; ?cstartup -- low-level system initialization code.
|
||||
;
|
||||
; After a reset execution starts here, the mode is ARM, supervisor
|
||||
; with interrupts disabled.
|
||||
;
|
||||
|
||||
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
EXTERN __cmain
|
||||
REQUIRE __vector
|
||||
EXTWEAK __iar_init_core
|
||||
EXTWEAK __iar_init_vfp
|
||||
|
||||
|
||||
ARM
|
||||
|
||||
__iar_program_start:
|
||||
?cstartup:
|
||||
|
||||
;
|
||||
; Add initialization needed before setup of stackpointers here.
|
||||
;
|
||||
|
||||
;
|
||||
; Initialize the stack pointers.
|
||||
; The pattern below can be used for any of the exception stacks:
|
||||
; FIQ, IRQ, SVC, ABT, UND, SYS.
|
||||
; The USR mode uses the same stack as SYS.
|
||||
; The stack segments must be defined in the linker command file,
|
||||
; and be declared above.
|
||||
;
|
||||
|
||||
|
||||
; --------------------
|
||||
; Mode, correspords to bits 0-5 in CPSR
|
||||
|
||||
#define MODE_MSK 0x1F ; Bit mask for mode bits in CPSR
|
||||
|
||||
#define USR_MODE 0x10 ; User mode
|
||||
#define FIQ_MODE 0x11 ; Fast Interrupt Request mode
|
||||
#define IRQ_MODE 0x12 ; Interrupt Request mode
|
||||
#define SVC_MODE 0x13 ; Supervisor mode
|
||||
#define ABT_MODE 0x17 ; Abort mode
|
||||
#define UND_MODE 0x1B ; Undefined Instruction mode
|
||||
#define SYS_MODE 0x1F ; System mode
|
||||
|
||||
|
||||
MRS r0, cpsr ; Original PSR value
|
||||
|
||||
;; Set up the interrupt stack pointer.
|
||||
|
||||
BIC r0, r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0, r0, #IRQ_MODE ; Set IRQ mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR r1, =SFE(IRQ_STACK) ; End of IRQ_STACK
|
||||
BIC sp,r1,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the fast interrupt stack pointer.
|
||||
|
||||
BIC r0, r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0, r0, #FIQ_MODE ; Set FIR mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR r1, =SFE(FIQ_STACK) ; End of FIQ_STACK
|
||||
BIC sp,r1,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the SVC stack pointer.
|
||||
|
||||
CPS #SVC_MODE
|
||||
LDR r1, =SFE(SVC_STACK) ; End of SVC_STACK
|
||||
BIC sp,r1,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the abort stack pointer.
|
||||
|
||||
CPS #ABT_MODE
|
||||
LDR r1, =SFE(ABT_STACK) ; End of ABT_STACK
|
||||
BIC sp,r1,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Set up the normal stack pointer.
|
||||
|
||||
BIC r0 ,r0, #MODE_MSK ; Clear the mode bits
|
||||
ORR r0 ,r0, #SYS_MODE ; Set System mode bits
|
||||
MSR cpsr_c, r0 ; Change the mode
|
||||
LDR r1, =SFE(CSTACK) ; End of CSTACK
|
||||
BIC sp,r1,#0x7 ; Make sure SP is 8 aligned
|
||||
|
||||
;; Turn on core features assumed to be enabled.
|
||||
FUNCALL __iar_program_start, __iar_init_core
|
||||
BL __iar_init_core
|
||||
|
||||
;; Initialize VFP (if needed).
|
||||
FUNCALL __iar_program_start, __iar_init_vfp
|
||||
BL __iar_init_vfp
|
||||
|
||||
;;;
|
||||
;;; Add more initialization here
|
||||
;;;
|
||||
|
||||
;;; Continue to __cmain for C-level initialization.
|
||||
|
||||
FUNCALL __iar_program_start, __cmain
|
||||
B __cmain
|
||||
|
||||
END
|
||||
376
ports_module/cortex_r4/iar/example_build/sample_threadx.c
Normal file
376
ports_module/cortex_r4/iar/example_build/sample_threadx.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight
|
||||
threads of different priorities, using a message queue, semaphore, mutex, event flags group,
|
||||
byte pool, and block pool. */
|
||||
|
||||
#include "tx_api.h"
|
||||
|
||||
#define DEMO_STACK_SIZE 1024
|
||||
#define DEMO_BYTE_POOL_SIZE 9120
|
||||
#define DEMO_BLOCK_POOL_SIZE 100
|
||||
#define DEMO_QUEUE_SIZE 100
|
||||
|
||||
|
||||
/* Define the ThreadX object control blocks... */
|
||||
|
||||
TX_THREAD thread_0;
|
||||
TX_THREAD thread_1;
|
||||
TX_THREAD thread_2;
|
||||
TX_THREAD thread_3;
|
||||
TX_THREAD thread_4;
|
||||
TX_THREAD thread_5;
|
||||
TX_THREAD thread_6;
|
||||
TX_THREAD thread_7;
|
||||
TX_QUEUE queue_0;
|
||||
TX_SEMAPHORE semaphore_0;
|
||||
TX_MUTEX mutex_0;
|
||||
TX_EVENT_FLAGS_GROUP event_flags_0;
|
||||
TX_BYTE_POOL byte_pool_0;
|
||||
TX_BLOCK_POOL block_pool_0;
|
||||
|
||||
|
||||
|
||||
/* Define byte pool memory. */
|
||||
|
||||
UCHAR byte_pool_memory[DEMO_BYTE_POOL_SIZE];
|
||||
|
||||
|
||||
|
||||
/* Define the counters used in the demo application... */
|
||||
|
||||
ULONG thread_0_counter;
|
||||
ULONG thread_1_counter;
|
||||
ULONG thread_1_messages_sent;
|
||||
ULONG thread_2_counter;
|
||||
ULONG thread_2_messages_received;
|
||||
ULONG thread_3_counter;
|
||||
ULONG thread_4_counter;
|
||||
ULONG thread_5_counter;
|
||||
ULONG thread_6_counter;
|
||||
ULONG thread_7_counter;
|
||||
|
||||
|
||||
/* Define thread prototypes. */
|
||||
|
||||
void thread_0_entry(ULONG thread_input);
|
||||
void thread_1_entry(ULONG thread_input);
|
||||
void thread_2_entry(ULONG thread_input);
|
||||
void thread_3_and_4_entry(ULONG thread_input);
|
||||
void thread_5_entry(ULONG thread_input);
|
||||
void thread_6_and_7_entry(ULONG thread_input);
|
||||
|
||||
|
||||
/* Define main entry point. */
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
/* Enter the ThreadX kernel. */
|
||||
tx_kernel_enter();
|
||||
}
|
||||
|
||||
|
||||
/* Define what the initial system looks like. */
|
||||
|
||||
void tx_application_define(void *first_unused_memory)
|
||||
{
|
||||
|
||||
CHAR *pointer = TX_NULL;
|
||||
|
||||
|
||||
/* Create a byte memory pool from which to allocate the thread stacks. */
|
||||
tx_byte_pool_create(&byte_pool_0, "byte pool 0", byte_pool_memory, DEMO_BYTE_POOL_SIZE);
|
||||
|
||||
/* Put system definition stuff in here, e.g. thread creates and other assorted
|
||||
create information. */
|
||||
|
||||
/* Allocate the stack for thread 0. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create the main thread. */
|
||||
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
|
||||
/* Allocate the stack for thread 1. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 1 and 2. These threads pass information through a ThreadX
|
||||
message queue. It is also interesting to note that these threads have a time
|
||||
slice. */
|
||||
tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
16, 16, 4, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 2. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
16, 16, 4, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 3. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
|
||||
An interesting thing here is that both threads share the same instruction area. */
|
||||
tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 4. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 5. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create thread 5. This thread simply pends on an event flag which will be set
|
||||
by thread_0. */
|
||||
tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 6. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
|
||||
tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 7. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the message queue. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
|
||||
|
||||
/* Create the message queue shared by threads 1 and 2. */
|
||||
tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
|
||||
|
||||
/* Create the semaphore used by threads 3 and 4. */
|
||||
tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
|
||||
|
||||
/* Create the event flags group used by threads 1 and 5. */
|
||||
tx_event_flags_create(&event_flags_0, "event flags 0");
|
||||
|
||||
/* Create the mutex used by thread 6 and 7 without priority inheritance. */
|
||||
tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
|
||||
|
||||
/* Allocate the memory for a small block pool. */
|
||||
tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create a block memory pool to allocate a message buffer from. */
|
||||
tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
|
||||
|
||||
/* Allocate a block and release the block memory. */
|
||||
tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
|
||||
|
||||
/* Release the block back to the pool. */
|
||||
tx_block_release(pointer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Define the test threads. */
|
||||
|
||||
void thread_0_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This thread simply sits in while-forever-sleep loop. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_0_counter++;
|
||||
|
||||
/* Sleep for 10 ticks. */
|
||||
tx_thread_sleep(10);
|
||||
|
||||
/* Set event flag 0 to wakeup thread 5. */
|
||||
status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_1_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This thread simply sends messages to a queue shared by thread 2. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_1_counter++;
|
||||
|
||||
/* Send message to queue 0. */
|
||||
status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check completion status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Increment the message sent. */
|
||||
thread_1_messages_sent++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_2_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
ULONG received_message;
|
||||
UINT status;
|
||||
|
||||
/* This thread retrieves messages placed on the queue by thread 1. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_2_counter++;
|
||||
|
||||
/* Retrieve a message from the queue. */
|
||||
status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check completion status and make sure the message is what we
|
||||
expected. */
|
||||
if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
|
||||
break;
|
||||
|
||||
/* Otherwise, all is okay. Increment the received message count. */
|
||||
thread_2_messages_received++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_3_and_4_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This function is executed from thread 3 and thread 4. As the loop
|
||||
below shows, these function compete for ownership of semaphore_0. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
if (thread_input == 3)
|
||||
thread_3_counter++;
|
||||
else
|
||||
thread_4_counter++;
|
||||
|
||||
/* Get the semaphore with suspension. */
|
||||
status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Sleep for 2 ticks to hold the semaphore. */
|
||||
tx_thread_sleep(2);
|
||||
|
||||
/* Release the semaphore. */
|
||||
status = tx_semaphore_put(&semaphore_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_5_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
ULONG actual_flags;
|
||||
|
||||
|
||||
/* This thread simply waits for an event in a forever loop. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_5_counter++;
|
||||
|
||||
/* Wait for event flag 0. */
|
||||
status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
|
||||
&actual_flags, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if ((status != TX_SUCCESS) || (actual_flags != 0x1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_6_and_7_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This function is executed from thread 6 and thread 7. As the loop
|
||||
below shows, these function compete for ownership of mutex_0. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
if (thread_input == 6)
|
||||
thread_6_counter++;
|
||||
else
|
||||
thread_7_counter++;
|
||||
|
||||
/* Get the mutex with suspension. */
|
||||
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Get the mutex again with suspension. This shows
|
||||
that an owning thread may retrieve the mutex it
|
||||
owns multiple times. */
|
||||
status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Sleep for 2 ticks to hold the mutex. */
|
||||
tx_thread_sleep(2);
|
||||
|
||||
/* Release the mutex. */
|
||||
status = tx_mutex_put(&mutex_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Release the mutex again. This will actually
|
||||
release ownership since it was obtained twice. */
|
||||
status = tx_mutex_put(&mutex_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
2974
ports_module/cortex_r4/iar/example_build/sample_threadx.ewd
Normal file
2974
ports_module/cortex_r4/iar/example_build/sample_threadx.ewd
Normal file
File diff suppressed because it is too large
Load Diff
2137
ports_module/cortex_r4/iar/example_build/sample_threadx.ewp
Normal file
2137
ports_module/cortex_r4/iar/example_build/sample_threadx.ewp
Normal file
File diff suppressed because it is too large
Load Diff
49
ports_module/cortex_r4/iar/example_build/sample_threadx.icf
Normal file
49
ports_module/cortex_r4/iar/example_build/sample_threadx.icf
Normal file
@@ -0,0 +1,49 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Specials-*/
|
||||
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x00000040;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x0013FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x08000000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x0802FFFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x200;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_fiqstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_undstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_abtstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x200;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define symbol __region_DRAM_start__ = 0x80000000;
|
||||
define symbol __region_DRAM_end__ = 0x807FFFFF;
|
||||
define region DRAM_region = mem:[from __region_DRAM_start__ to __region_DRAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block FIQ_STACK with alignment = 8, size = __ICFEDIT_size_fiqstack__ { };
|
||||
define block UND_STACK with alignment = 8, size = __ICFEDIT_size_undstack__ { };
|
||||
define block ABT_STACK with alignment = 8, size = __ICFEDIT_size_abtstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
|
||||
|
||||
place in ROM_region { readonly };
|
||||
place in RAM_region { readwrite,
|
||||
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
|
||||
block UND_STACK, block ABT_STACK, block HEAP};
|
||||
place in DRAM_region { section DRAM };
|
||||
|
||||
place in RAM_region { last section FREE_MEM};
|
||||
425
ports_module/cortex_r4/iar/example_build/sample_threadx_module.c
Normal file
425
ports_module/cortex_r4/iar/example_build/sample_threadx_module.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/* This is a small demo of the high-performance ThreadX kernel running as a module. It includes
|
||||
examples of eight threads of different priorities, using a message queue, semaphore, mutex,
|
||||
event flags group, byte pool, and block pool. */
|
||||
|
||||
/* Specify that this is a module! */
|
||||
|
||||
#define TXM_MODULE
|
||||
|
||||
|
||||
/* Include the ThreadX module definitions. */
|
||||
|
||||
#include "txm_module.h"
|
||||
|
||||
|
||||
/* Define constants. */
|
||||
|
||||
#define DEMO_STACK_SIZE 1024
|
||||
#define DEMO_BYTE_POOL_SIZE 9120
|
||||
#define DEMO_BLOCK_POOL_SIZE 100
|
||||
#define DEMO_QUEUE_SIZE 100
|
||||
|
||||
|
||||
/* Define the pool space in the bss section of the module. ULONG is used to
|
||||
get the word alignment. */
|
||||
|
||||
ULONG demo_module_pool_space[DEMO_BYTE_POOL_SIZE / 4];
|
||||
|
||||
|
||||
/* Define the ThreadX object control blocks... */
|
||||
|
||||
TX_THREAD *thread_0;
|
||||
TX_THREAD *thread_1;
|
||||
TX_THREAD *thread_2;
|
||||
TX_THREAD *thread_3;
|
||||
TX_THREAD *thread_4;
|
||||
TX_THREAD *thread_5;
|
||||
TX_THREAD *thread_6;
|
||||
TX_THREAD *thread_7;
|
||||
TX_QUEUE *queue_0;
|
||||
TX_SEMAPHORE *semaphore_0;
|
||||
TX_MUTEX *mutex_0;
|
||||
TX_EVENT_FLAGS_GROUP *event_flags_0;
|
||||
TX_BYTE_POOL *byte_pool_0;
|
||||
TX_BLOCK_POOL *block_pool_0;
|
||||
|
||||
|
||||
/* Define the counters used in the demo application... */
|
||||
|
||||
ULONG thread_0_counter;
|
||||
ULONG thread_1_counter;
|
||||
ULONG thread_1_messages_sent;
|
||||
ULONG thread_2_counter;
|
||||
ULONG thread_2_messages_received;
|
||||
ULONG thread_3_counter;
|
||||
ULONG thread_4_counter;
|
||||
ULONG thread_5_counter;
|
||||
ULONG thread_6_counter;
|
||||
ULONG thread_7_counter;
|
||||
ULONG semaphore_0_puts;
|
||||
ULONG event_0_sets;
|
||||
ULONG queue_0_sends;
|
||||
|
||||
/* Define thread prototypes. */
|
||||
|
||||
void thread_0_entry(ULONG thread_input);
|
||||
void thread_1_entry(ULONG thread_input);
|
||||
void thread_2_entry(ULONG thread_input);
|
||||
void thread_3_and_4_entry(ULONG thread_input);
|
||||
void thread_5_entry(ULONG thread_input);
|
||||
void thread_6_and_7_entry(ULONG thread_input);
|
||||
|
||||
void semaphore_0_notify(TX_SEMAPHORE *semaphore_ptr)
|
||||
{
|
||||
|
||||
if (semaphore_ptr == semaphore_0)
|
||||
semaphore_0_puts++;
|
||||
}
|
||||
|
||||
|
||||
void event_0_notify(TX_EVENT_FLAGS_GROUP *event_flag_group_ptr)
|
||||
{
|
||||
|
||||
if (event_flag_group_ptr == event_flags_0)
|
||||
event_0_sets++;
|
||||
}
|
||||
|
||||
|
||||
void queue_0_notify(TX_QUEUE *queue_ptr)
|
||||
{
|
||||
|
||||
if (queue_ptr == queue_0)
|
||||
queue_0_sends++;
|
||||
}
|
||||
|
||||
|
||||
/* Define the module start function. */
|
||||
|
||||
void demo_module_start(ULONG id)
|
||||
{
|
||||
|
||||
CHAR *pointer;
|
||||
|
||||
/* Allocate all the objects. In MPU mode, modules cannot allocate control blocks within
|
||||
their own memory area so they cannot corrupt the resident portion of ThreadX by overwriting
|
||||
the control block(s). */
|
||||
txm_module_object_allocate((void*)&thread_0, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_1, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_2, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_3, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_4, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_5, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_6, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&thread_7, sizeof(TX_THREAD));
|
||||
txm_module_object_allocate((void*)&queue_0, sizeof(TX_QUEUE));
|
||||
txm_module_object_allocate((void*)&semaphore_0, sizeof(TX_SEMAPHORE));
|
||||
txm_module_object_allocate((void*)&mutex_0, sizeof(TX_MUTEX));
|
||||
txm_module_object_allocate((void*)&event_flags_0, sizeof(TX_EVENT_FLAGS_GROUP));
|
||||
txm_module_object_allocate((void*)&byte_pool_0, sizeof(TX_BYTE_POOL));
|
||||
txm_module_object_allocate((void*)&block_pool_0, sizeof(TX_BLOCK_POOL));
|
||||
|
||||
|
||||
/* Create a byte memory pool from which to allocate the thread stacks. */
|
||||
tx_byte_pool_create(byte_pool_0, "module byte pool 0", demo_module_pool_space, DEMO_BYTE_POOL_SIZE);
|
||||
|
||||
/* Put system definition stuff in here, e.g. thread creates and other assorted
|
||||
create information. */
|
||||
|
||||
/* Allocate the stack for thread 0. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create the main thread. */
|
||||
tx_thread_create(thread_0, "module thread 0", thread_0_entry, 0,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
|
||||
/* Allocate the stack for thread 1. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 1 and 2. These threads pass information through a ThreadX
|
||||
message queue. It is also interesting to note that these threads have a time
|
||||
slice. */
|
||||
tx_thread_create(thread_1, "module thread 1", thread_1_entry, 1,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
16, 16, 4, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 2. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(thread_2, "module thread 2", thread_2_entry, 2,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
16, 16, 4, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 3. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
|
||||
An interesting thing here is that both threads share the same instruction area. */
|
||||
tx_thread_create(thread_3, "module thread 3", thread_3_and_4_entry, 3,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 4. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(thread_4, "module thread 4", thread_3_and_4_entry, 4,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 5. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create thread 5. This thread simply pends on an event flag which will be set
|
||||
by thread_0. */
|
||||
tx_thread_create(thread_5, "module thread 5", thread_5_entry, 5,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 6. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
|
||||
tx_thread_create(thread_6, "module thread 6", thread_6_and_7_entry, 6,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the stack for thread 7. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
|
||||
|
||||
tx_thread_create(thread_7, "module thread 7", thread_6_and_7_entry, 7,
|
||||
pointer, DEMO_STACK_SIZE,
|
||||
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
|
||||
/* Allocate the message queue. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
|
||||
|
||||
/* Create the message queue shared by threads 1 and 2. */
|
||||
tx_queue_create(queue_0, "module queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
|
||||
|
||||
tx_queue_send_notify(queue_0, queue_0_notify);
|
||||
|
||||
/* Create the semaphore used by threads 3 and 4. */
|
||||
tx_semaphore_create(semaphore_0, "module semaphore 0", 1);
|
||||
|
||||
tx_semaphore_put_notify(semaphore_0, semaphore_0_notify);
|
||||
|
||||
/* Create the event flags group used by threads 1 and 5. */
|
||||
tx_event_flags_create(event_flags_0, "module event flags 0");
|
||||
|
||||
tx_event_flags_set_notify(event_flags_0, event_0_notify);
|
||||
|
||||
/* Create the mutex used by thread 6 and 7 without priority inheritance. */
|
||||
tx_mutex_create(mutex_0, "module mutex 0", TX_NO_INHERIT);
|
||||
|
||||
/* Allocate the memory for a small block pool. */
|
||||
tx_byte_allocate(byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
|
||||
|
||||
/* Create a block memory pool to allocate a message buffer from. */
|
||||
tx_block_pool_create(block_pool_0, "module block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
|
||||
|
||||
/* Allocate a block and release the block memory. */
|
||||
tx_block_allocate(block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
|
||||
|
||||
/* Release the block back to the pool. */
|
||||
tx_block_release(pointer);
|
||||
}
|
||||
|
||||
|
||||
/* Define the test threads. */
|
||||
|
||||
void thread_0_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This thread simply sits in while-forever-sleep loop. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_0_counter++;
|
||||
|
||||
/* Sleep for 10 ticks. */
|
||||
tx_thread_sleep(10);
|
||||
|
||||
/* Set event flag 0 to wakeup thread 5. */
|
||||
status = tx_event_flags_set(event_flags_0, 0x1, TX_OR);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_1_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This thread simply sends messages to a queue shared by thread 2. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_1_counter++;
|
||||
|
||||
/* Send message to queue 0. */
|
||||
status = tx_queue_send(queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check completion status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Increment the message sent. */
|
||||
thread_1_messages_sent++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_2_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
ULONG received_message;
|
||||
UINT status;
|
||||
|
||||
/* This thread retrieves messages placed on the queue by thread 1. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_2_counter++;
|
||||
|
||||
/* Retrieve a message from the queue. */
|
||||
status = tx_queue_receive(queue_0, &received_message, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check completion status and make sure the message is what we
|
||||
expected. */
|
||||
if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
|
||||
break;
|
||||
|
||||
/* Otherwise, all is okay. Increment the received message count. */
|
||||
thread_2_messages_received++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_3_and_4_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This function is executed from thread 3 and thread 4. As the loop
|
||||
below shows, these function compete for ownership of semaphore_0. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
if (thread_input == 3)
|
||||
thread_3_counter++;
|
||||
else
|
||||
thread_4_counter++;
|
||||
|
||||
/* Get the semaphore with suspension. */
|
||||
status = tx_semaphore_get(semaphore_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Sleep for 2 ticks to hold the semaphore. */
|
||||
tx_thread_sleep(2);
|
||||
|
||||
/* Release the semaphore. */
|
||||
status = tx_semaphore_put(semaphore_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_5_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
ULONG actual_flags;
|
||||
|
||||
|
||||
/* This thread simply waits for an event in a forever loop. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
thread_5_counter++;
|
||||
|
||||
/* Wait for event flag 0. */
|
||||
status = tx_event_flags_get(event_flags_0, 0x1, TX_OR_CLEAR,
|
||||
&actual_flags, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if ((status != TX_SUCCESS) || (actual_flags != 0x1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void thread_6_and_7_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* This function is executed from thread 6 and thread 7. As the loop
|
||||
below shows, these function compete for ownership of mutex_0. */
|
||||
while(1)
|
||||
{
|
||||
|
||||
/* Increment the thread counter. */
|
||||
if (thread_input == 6)
|
||||
thread_6_counter++;
|
||||
else
|
||||
thread_7_counter++;
|
||||
|
||||
/* Get the mutex with suspension. */
|
||||
status = tx_mutex_get(mutex_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Get the mutex again with suspension. This shows
|
||||
that an owning thread may retrieve the mutex it
|
||||
owns multiple times. */
|
||||
status = tx_mutex_get(mutex_0, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Sleep for 2 ticks to hold the mutex. */
|
||||
tx_thread_sleep(2);
|
||||
|
||||
/* Release the mutex. */
|
||||
status = tx_mutex_put(mutex_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
|
||||
/* Release the mutex again. This will actually
|
||||
release ownership since it was obtained twice. */
|
||||
status = tx_mutex_put(mutex_0);
|
||||
|
||||
/* Check status. */
|
||||
if (status != TX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2974
ports_module/cortex_r4/iar/example_build/sample_threadx_module.ewd
Normal file
2974
ports_module/cortex_r4/iar/example_build/sample_threadx_module.ewd
Normal file
File diff suppressed because it is too large
Load Diff
2135
ports_module/cortex_r4/iar/example_build/sample_threadx_module.ewp
Normal file
2135
ports_module/cortex_r4/iar/example_build/sample_threadx_module.ewp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Specials-*/
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x00100000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x0013FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x08000000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x0800FFFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_cstack__ = 0;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0;
|
||||
define symbol __ICFEDIT_size_fiqstack__ = 0;
|
||||
define symbol __ICFEDIT_size_undstack__ = 0;
|
||||
define symbol __ICFEDIT_size_abtstack__ = 0;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x100;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
define movable block ROPI with alignment = 4, fixed order
|
||||
{
|
||||
ro object txm_module_preamble.o,
|
||||
ro,
|
||||
ro data
|
||||
};
|
||||
|
||||
define movable block RWPI with alignment = 8, fixed order, static base
|
||||
{
|
||||
rw,
|
||||
block HEAP
|
||||
};
|
||||
|
||||
place in ROM_region { block ROPI };
|
||||
place in RAM_region { block RWPI };
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Small demonstration of the ThreadX module manager. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
#define DEMO_STACK_SIZE 1024
|
||||
|
||||
/* Define the ThreadX object control blocks... */
|
||||
|
||||
TX_THREAD module_manager;
|
||||
TXM_MODULE_INSTANCE my_module;
|
||||
|
||||
UCHAR manager_stack[1024];
|
||||
|
||||
/* Define the object pool area. */
|
||||
|
||||
UCHAR object_memory[8192];
|
||||
|
||||
|
||||
/* Define the count of memory faults. */
|
||||
|
||||
ULONG memory_faults;
|
||||
|
||||
|
||||
/* Define thread prototypes. */
|
||||
|
||||
void module_manager_entry(ULONG thread_input);
|
||||
|
||||
|
||||
/* Define fault handler. */
|
||||
|
||||
VOID module_fault_handler(TX_THREAD *thread, TXM_MODULE_INSTANCE *module)
|
||||
{
|
||||
|
||||
/* Just increment the fault counter. */
|
||||
memory_faults++;
|
||||
}
|
||||
|
||||
/* Define main entry point. */
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
/* Enter the ThreadX kernel. */
|
||||
tx_kernel_enter();
|
||||
}
|
||||
|
||||
|
||||
/* Define what the initial system looks like. */
|
||||
|
||||
void tx_application_define(void *first_unused_memory)
|
||||
{
|
||||
tx_thread_create(&module_manager, "Module Manager Thread", module_manager_entry, 0,
|
||||
manager_stack, DEMO_STACK_SIZE,
|
||||
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Define the test threads. */
|
||||
|
||||
void module_manager_entry(ULONG thread_input)
|
||||
{
|
||||
|
||||
/* Initialize the module manager. */
|
||||
txm_module_manager_initialize((VOID *) 0x08020000, 0x10000);
|
||||
|
||||
txm_module_manager_object_pool_create(object_memory, sizeof(object_memory));
|
||||
|
||||
/* Register a fault handler. */
|
||||
txm_module_manager_memory_fault_notify(module_fault_handler);
|
||||
|
||||
/* Load the module that is already there, in this example it is placed there by the multiple image download. */
|
||||
txm_module_manager_in_place_load(&my_module, "my module", (VOID *) 0x00100000);
|
||||
|
||||
/* Enable 128 byte read/write shared memory region at 0x08025000. */
|
||||
txm_module_manager_external_memory_enable(&my_module, (void *) 0x08025000, 128, TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE);
|
||||
|
||||
/* Start the module. */
|
||||
txm_module_manager_start(&my_module);
|
||||
|
||||
/* Sleep for a while.... */
|
||||
tx_thread_sleep(300);
|
||||
|
||||
/* Stop the module. */
|
||||
txm_module_manager_stop(&my_module);
|
||||
|
||||
/* Unload the module. */
|
||||
txm_module_manager_unload(&my_module);
|
||||
|
||||
/* Load the module that is already there. */
|
||||
txm_module_manager_in_place_load(&my_module, "my module", (VOID *) 0x00100000);
|
||||
|
||||
/* Start the module again. */
|
||||
txm_module_manager_start(&my_module);
|
||||
|
||||
/* Now just spin... */
|
||||
while(1)
|
||||
{
|
||||
|
||||
tx_thread_sleep(100);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Specials-*/
|
||||
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x00000040;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x000FFFFF; //Module in 0x00100000-0x0013FFFF
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x08000000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x0801FFFF; //Module in 0x08020000-0x0802FFFF
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x200;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_fiqstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_undstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_abtstack__ = 0x100;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x200;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define symbol __region_DRAM_start__ = 0x80000000;
|
||||
define symbol __region_DRAM_end__ = 0x807FFFFF;
|
||||
define region DRAM_region = mem:[from __region_DRAM_start__ to __region_DRAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block FIQ_STACK with alignment = 8, size = __ICFEDIT_size_fiqstack__ { };
|
||||
define block UND_STACK with alignment = 8, size = __ICFEDIT_size_undstack__ { };
|
||||
define block ABT_STACK with alignment = 8, size = __ICFEDIT_size_abtstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy with packing = none { section __DLIB_PERTHREAD }; // Required in a multi-threaded application
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
|
||||
|
||||
place in ROM_region { readonly };
|
||||
place in RAM_region { readwrite,
|
||||
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
|
||||
block UND_STACK, block ABT_STACK, block HEAP};
|
||||
place in DRAM_region { section DRAM };
|
||||
|
||||
place in RAM_region { last section FREE_MEM};
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0"?>
|
||||
<settings>
|
||||
<Stack>
|
||||
<FillEnabled>0</FillEnabled>
|
||||
<OverflowWarningsEnabled>1</OverflowWarningsEnabled>
|
||||
<WarningThreshold>90</WarningThreshold>
|
||||
<SpWarningsEnabled>1</SpWarningsEnabled>
|
||||
<WarnLogOnly>1</WarnLogOnly>
|
||||
<UseTrigger>1</UseTrigger>
|
||||
<TriggerName>main</TriggerName>
|
||||
<LimitSize>0</LimitSize>
|
||||
<ByteLimit>50</ByteLimit>
|
||||
</Stack>
|
||||
<Trace1>
|
||||
<Enabled>0</Enabled>
|
||||
<ShowSource>1</ShowSource>
|
||||
</Trace1>
|
||||
<DebugChecksum>
|
||||
<Checksum>157308190</Checksum>
|
||||
</DebugChecksum>
|
||||
<Disassembly>
|
||||
<InstrCount>0</InstrCount>
|
||||
<MixedMode>1</MixedMode>
|
||||
</Disassembly>
|
||||
<CodeCoverage>
|
||||
<Enabled>0</Enabled>
|
||||
<ShowSource>0</ShowSource>
|
||||
<HideCovered>0</HideCovered>
|
||||
</CodeCoverage>
|
||||
<DriverProfiling>
|
||||
<Enabled>0</Enabled>
|
||||
<Mode>1</Mode>
|
||||
<Graph>0</Graph>
|
||||
<Symbiont>0</Symbiont>
|
||||
</DriverProfiling>
|
||||
<CallStackLog>
|
||||
<Enabled>0</Enabled>
|
||||
</CallStackLog>
|
||||
<CallStackStripe>
|
||||
<ShowTiming>1</ShowTiming>
|
||||
</CallStackStripe>
|
||||
<Exceptions>
|
||||
<StopOnUncaught>_ 0</StopOnUncaught>
|
||||
<StopOnThrow>_ 0</StopOnThrow>
|
||||
</Exceptions>
|
||||
<TermIOLog>
|
||||
<LoggingEnabled>_ 0</LoggingEnabled>
|
||||
<LogFile>_ ""</LogFile>
|
||||
</TermIOLog>
|
||||
<LogFile>
|
||||
<LoggingEnabled>_ 0</LoggingEnabled>
|
||||
<LogFile>_ ""</LogFile>
|
||||
<Category>_ 0</Category>
|
||||
</LogFile>
|
||||
<CallStack>
|
||||
<ShowArgs>0</ShowArgs>
|
||||
</CallStack>
|
||||
<InterruptLog>
|
||||
<LogEnabled>0</LogEnabled>
|
||||
<GraphEnabled>0</GraphEnabled>
|
||||
<ShowTimeLog>1</ShowTimeLog>
|
||||
<SumEnabled>0</SumEnabled>
|
||||
<ShowTimeSum>1</ShowTimeSum>
|
||||
<SumSortOrder>0</SumSortOrder>
|
||||
</InterruptLog>
|
||||
<DataLog>
|
||||
<LogEnabled>0</LogEnabled>
|
||||
<GraphEnabled>0</GraphEnabled>
|
||||
<ShowTimeLog>1</ShowTimeLog>
|
||||
<SumEnabled>0</SumEnabled>
|
||||
<ShowTimeSum>1</ShowTimeSum>
|
||||
</DataLog>
|
||||
<DisassembleMode>
|
||||
<mode>0</mode>
|
||||
</DisassembleMode>
|
||||
<Breakpoints2>
|
||||
<Count>0</Count>
|
||||
</Breakpoints2>
|
||||
<Interrupts>
|
||||
<Enabled>1</Enabled>
|
||||
<Irq0>_ 0 10000 0 10000 1 0 0 100 0 1 "IRQ 1 0x18 CPSR.I"</Irq0>
|
||||
<Count>1</Count>
|
||||
</Interrupts>
|
||||
<MemConfig>
|
||||
<Base>1</Base>
|
||||
<Manual>0</Manual>
|
||||
<Ddf>1</Ddf>
|
||||
<TypeViol>0</TypeViol>
|
||||
<Stop>1</Stop>
|
||||
</MemConfig>
|
||||
<Aliases>
|
||||
<Count>0</Count>
|
||||
<SuppressDialog>0</SuppressDialog>
|
||||
</Aliases>
|
||||
<Simulator>
|
||||
<Freq>10000000</Freq>
|
||||
<FreqHi>0</FreqHi>
|
||||
<MultiCoreRunAll>1</MultiCoreRunAll>
|
||||
</Simulator>
|
||||
</settings>
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0"?>
|
||||
<settings>
|
||||
<DebugChecksum>
|
||||
<Checksum>1819642867</Checksum>
|
||||
</DebugChecksum>
|
||||
<Stack>
|
||||
<FillEnabled>0</FillEnabled>
|
||||
<OverflowWarningsEnabled>1</OverflowWarningsEnabled>
|
||||
<WarningThreshold>90</WarningThreshold>
|
||||
<SpWarningsEnabled>1</SpWarningsEnabled>
|
||||
<WarnLogOnly>1</WarnLogOnly>
|
||||
<UseTrigger>1</UseTrigger>
|
||||
<TriggerName>main</TriggerName>
|
||||
<LimitSize>0</LimitSize>
|
||||
<ByteLimit>50</ByteLimit>
|
||||
</Stack>
|
||||
<Disassembly>
|
||||
<InstrCount>0</InstrCount>
|
||||
<MixedMode>1</MixedMode>
|
||||
</Disassembly>
|
||||
<CodeCoverage>
|
||||
<Enabled>0</Enabled>
|
||||
<ShowSource>0</ShowSource>
|
||||
<HideCovered>0</HideCovered>
|
||||
</CodeCoverage>
|
||||
<Trace1>
|
||||
<Enabled>0</Enabled>
|
||||
<ShowSource>1</ShowSource>
|
||||
</Trace1>
|
||||
<Exceptions>
|
||||
<StopOnUncaught>_ 0</StopOnUncaught>
|
||||
<StopOnThrow>_ 0</StopOnThrow>
|
||||
</Exceptions>
|
||||
<CallStack>
|
||||
<ShowArgs>0</ShowArgs>
|
||||
</CallStack>
|
||||
<DriverProfiling>
|
||||
<Enabled>0</Enabled>
|
||||
<Mode>1</Mode>
|
||||
<Graph>0</Graph>
|
||||
<Symbiont>0</Symbiont>
|
||||
</DriverProfiling>
|
||||
<CallStackLog>
|
||||
<Enabled>0</Enabled>
|
||||
</CallStackLog>
|
||||
<CallStackStripe>
|
||||
<ShowTiming>1</ShowTiming>
|
||||
</CallStackStripe>
|
||||
<TermIOLog>
|
||||
<LoggingEnabled>_ 0</LoggingEnabled>
|
||||
<LogFile>_ ""</LogFile>
|
||||
</TermIOLog>
|
||||
<LogFile>
|
||||
<LoggingEnabled>_ 0</LoggingEnabled>
|
||||
<LogFile>_ ""</LogFile>
|
||||
<Category>_ 0</Category>
|
||||
</LogFile>
|
||||
<InterruptLog>
|
||||
<LogEnabled>0</LogEnabled>
|
||||
<GraphEnabled>0</GraphEnabled>
|
||||
<ShowTimeLog>1</ShowTimeLog>
|
||||
<SumEnabled>0</SumEnabled>
|
||||
<ShowTimeSum>1</ShowTimeSum>
|
||||
<SumSortOrder>0</SumSortOrder>
|
||||
</InterruptLog>
|
||||
<DataLog>
|
||||
<LogEnabled>0</LogEnabled>
|
||||
<GraphEnabled>0</GraphEnabled>
|
||||
<ShowTimeLog>1</ShowTimeLog>
|
||||
<SumEnabled>0</SumEnabled>
|
||||
<ShowTimeSum>1</ShowTimeSum>
|
||||
</DataLog>
|
||||
<DisassembleMode>
|
||||
<mode>0</mode>
|
||||
</DisassembleMode>
|
||||
<Breakpoints2>
|
||||
<Count>0</Count>
|
||||
</Breakpoints2>
|
||||
<Interrupts>
|
||||
<Enabled>1</Enabled>
|
||||
<Irq0>_ 0 10000 0 10000 1 0 0 100 0 1 "IRQ 1 0x18 CPSR.I"</Irq0>
|
||||
<Count>1</Count>
|
||||
</Interrupts>
|
||||
<MemConfig>
|
||||
<Base>1</Base>
|
||||
<Manual>0</Manual>
|
||||
<Ddf>1</Ddf>
|
||||
<TypeViol>0</TypeViol>
|
||||
<Stop>1</Stop>
|
||||
</MemConfig>
|
||||
<Aliases>
|
||||
<Count>0</Count>
|
||||
<SuppressDialog>0</SuppressDialog>
|
||||
</Aliases>
|
||||
<Simulator>
|
||||
<Freq>10000000</Freq>
|
||||
<FreqHi>0</FreqHi>
|
||||
<MultiCoreRunAll>1</MultiCoreRunAll>
|
||||
</Simulator>
|
||||
</settings>
|
||||
2974
ports_module/cortex_r4/iar/example_build/tx.ewd
Normal file
2974
ports_module/cortex_r4/iar/example_build/tx.ewd
Normal file
File diff suppressed because it is too large
Load Diff
2880
ports_module/cortex_r4/iar/example_build/tx.ewp
Normal file
2880
ports_module/cortex_r4/iar/example_build/tx.ewp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,408 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Initialize */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;#define TX_SOURCE_CODE
|
||||
;
|
||||
;
|
||||
;/* Include necessary system files. */
|
||||
;
|
||||
;#include "tx_api.h"
|
||||
;#include "tx_initialize.h"
|
||||
;#include "tx_thread.h"
|
||||
;#include "tx_timer.h"
|
||||
;
|
||||
;
|
||||
SVC_MODE DEFINE 0x13 ; SVC mode
|
||||
ABT_MODE DEFINE 0x17 ; ABT mode
|
||||
SYS_MODE DEFINE 0x1F ; SYS mode
|
||||
THUMB_MASK DEFINE 0x20 ; Thumb bit (5) of CPSR/SPSR
|
||||
;
|
||||
|
||||
EXTERN _tx_thread_system_stack_ptr
|
||||
EXTERN _tx_initialize_unused_memory
|
||||
EXTERN _tx_thread_context_save
|
||||
; EXTERN _tx_thread_vectored_context_save
|
||||
EXTERN _tx_thread_context_restore
|
||||
|
||||
#ifdef TX_ENABLE_IRQ_NESTING
|
||||
EXTERN _tx_thread_irq_nesting_start
|
||||
EXTERN _tx_thread_irq_nesting_end
|
||||
#endif
|
||||
|
||||
EXTERN _tx_timer_interrupt
|
||||
EXTERN ?cstartup
|
||||
EXTERN _tx_build_options
|
||||
EXTERN _tx_version_id
|
||||
;
|
||||
;
|
||||
;
|
||||
;/* Define the FREE_MEM segment that will specify where free memory is
|
||||
; defined. This must also be located in at the end of other RAM segments
|
||||
; in the linker control file. The value of this segment is what is passed
|
||||
; to tx_application_define. */
|
||||
;
|
||||
RSEG FREE_MEM:DATA
|
||||
PUBLIC __tx_free_memory_start
|
||||
__tx_free_memory_start
|
||||
DS32 4
|
||||
;
|
||||
;
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_initialize_low_level Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is responsible for any low-level processor */
|
||||
;/* initialization, including setting up interrupt vectors, setting */
|
||||
;/* up a periodic timer interrupt source, saving the system stack */
|
||||
;/* pointer for use in ISR processing later, and finding the first */
|
||||
;/* available RAM memory address for tx_application_define. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* _tx_initialize_kernel_enter ThreadX entry function */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_initialize_low_level(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
ARM
|
||||
PUBLIC _tx_initialize_low_level
|
||||
_tx_initialize_low_level
|
||||
;
|
||||
; /****** NOTE ****** The IAR 4.11a and above releases call main in SYS mode. */
|
||||
;
|
||||
; /* For modules, stay in SYS mode and disable interrupts. */
|
||||
CPSID i
|
||||
;
|
||||
; /* Pickup the start of free memory. */
|
||||
;
|
||||
LDR r0, =__tx_free_memory_start ; Get end of non-initialized RAM area
|
||||
;
|
||||
; /* Save the system stack pointer. */
|
||||
; _tx_thread_system_stack_ptr = (VOID_PTR) (sp);
|
||||
;
|
||||
; /* Save the first available memory address. */
|
||||
; _tx_initialize_unused_memory = (VOID_PTR) FREE_MEM;
|
||||
;
|
||||
LDR r2, =_tx_initialize_unused_memory ; Pickup unused memory ptr address
|
||||
STR r0, [r2, #0] ; Save first free memory address
|
||||
;
|
||||
; /* Setup Timer for periodic interrupts. */
|
||||
;
|
||||
; /* Done, return to caller. */
|
||||
;
|
||||
BX lr ; Return to caller
|
||||
;}
|
||||
;
|
||||
;/* Define shells for each of the interrupt vectors. */
|
||||
;
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC __tx_undefined
|
||||
__tx_undefined
|
||||
B __tx_undefined ; Undefined handler
|
||||
;
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC __tx_reserved_handler
|
||||
__tx_reserved_handler
|
||||
B __tx_reserved_handler ; Reserved exception handler
|
||||
;
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC __tx_irq_handler
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC __tx_irq_processing_return
|
||||
PUBLIC IRQ_Handler
|
||||
__tx_irq_handler
|
||||
IRQ_Handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
B _tx_thread_context_save
|
||||
__tx_irq_processing_return
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. In
|
||||
; addition, IRQ interrupts may be re-enabled - with certain restrictions -
|
||||
; if nested IRQ interrupts are desired. Interrupts may be re-enabled over
|
||||
; small code sequences where lr is saved before enabling interrupts and
|
||||
; restored after interrupts are again disabled. */
|
||||
;
|
||||
; /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
|
||||
; from IRQ mode with interrupts disabled. This routine switches to the
|
||||
; system mode and returns with IRQ interrupts enabled.
|
||||
;
|
||||
; NOTE: It is very important to ensure all IRQ interrupts are cleared
|
||||
; prior to enabling nested IRQ interrupts. */
|
||||
#ifdef TX_ENABLE_IRQ_NESTING
|
||||
BL _tx_thread_irq_nesting_start
|
||||
#endif
|
||||
;
|
||||
; /* For debug purpose, execute the timer interrupt processing here. In
|
||||
; a real system, some kind of status indication would have to be checked
|
||||
; before the timer interrupt handler could be called. */
|
||||
;
|
||||
BL _tx_timer_interrupt ; Timer interrupt handler
|
||||
;
|
||||
; /* Application IRQ handlers can be called here! */
|
||||
;
|
||||
; /* If interrupt nesting was started earlier, the end of interrupt nesting
|
||||
; service must be called before returning to _tx_thread_context_restore.
|
||||
; This routine returns in processing in IRQ mode with interrupts disabled. */
|
||||
#ifdef TX_ENABLE_IRQ_NESTING
|
||||
BL _tx_thread_irq_nesting_end
|
||||
#endif
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
B _tx_thread_context_restore
|
||||
;
|
||||
;
|
||||
; /* This is an example of a vectored IRQ handler. */
|
||||
;
|
||||
; RSEG .text:CODE:NOROOT(2)
|
||||
; PUBLIC __tx_example_vectored_irq_handler
|
||||
;__tx_example_vectored_irq_handler
|
||||
;
|
||||
; /* Jump to context save to save system context. */
|
||||
; STMDB sp!, {r0-r3} ; Save some scratch registers
|
||||
; MRS r0, SPSR ; Pickup saved SPSR
|
||||
; SUB lr, lr, #4 ; Adjust point of interrupt
|
||||
; STMDB sp!, {r0, r10, r12, lr} ; Store other registers
|
||||
; BL _tx_thread_vectored_context_save
|
||||
;
|
||||
; /* At this point execution is still in the IRQ mode. The CPSR, point of
|
||||
; interrupt, and all C scratch registers are available for use. In
|
||||
; addition, IRQ interrupts may be re-enabled - with certain restrictions -
|
||||
; if nested IRQ interrupts are desired. Interrupts may be re-enabled over
|
||||
; small code sequences where lr is saved before enabling interrupts and
|
||||
; restored after interrupts are again disabled. */
|
||||
;
|
||||
; /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start
|
||||
; from IRQ mode with interrupts disabled. This routine switches to the
|
||||
; system mode and returns with IRQ interrupts enabled.
|
||||
;
|
||||
; NOTE: It is very important to ensure all IRQ interrupts are cleared
|
||||
; prior to enabling nested IRQ interrupts. */
|
||||
;#ifdef TX_ENABLE_IRQ_NESTING
|
||||
; BL _tx_thread_irq_nesting_start
|
||||
;#endif
|
||||
;
|
||||
; /* Application IRQ handler is called here! */
|
||||
;
|
||||
; /* If interrupt nesting was started earlier, the end of interrupt nesting
|
||||
; service must be called before returning to _tx_thread_context_restore.
|
||||
; This routine returns in processing in IRQ mode with interrupts disabled. */
|
||||
;#ifdef TX_ENABLE_IRQ_NESTING
|
||||
; BL _tx_thread_irq_nesting_end
|
||||
;#endif
|
||||
;
|
||||
; /* Jump to context restore to restore system context. */
|
||||
; B _tx_thread_context_restore
|
||||
;
|
||||
;
|
||||
; /* FIQ Handler */
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC __tx_fiq_handler
|
||||
__tx_fiq_handler
|
||||
B __tx_fiq_handler ; FIQ interrupt handler
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* __tx_prefetch_handler & __tx_abort_handler Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function handles MPU exceptions and fills the */
|
||||
;/* _txm_module_manager_memory_fault_info struct. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* _txm_module_manager_memory_fault_handler */
|
||||
;/* _tx_execution_thread_exit */
|
||||
;/* _tx_thread_schedule */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* MMU exceptions */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
|
||||
; *******************************************************************
|
||||
; MPU Exception Handling
|
||||
; *******************************************************************
|
||||
EXTERN _tx_thread_system_state
|
||||
EXTERN _txm_module_manager_memory_fault_info
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _txm_module_manager_memory_fault_handler
|
||||
EXTERN _tx_execution_thread_exit
|
||||
EXTERN _tx_thread_schedule
|
||||
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC Prefetch_Handler
|
||||
PUBLIC Abort_Handler
|
||||
PUBLIC __tx_prefetch_handler
|
||||
PUBLIC __tx_abort_handler
|
||||
__tx_prefetch_handler
|
||||
__tx_abort_handler
|
||||
Prefetch_Handler
|
||||
Abort_Handler
|
||||
STMDB sp!, {r0-r3} ; Save some working registers
|
||||
LDR r3, =_tx_thread_system_state ; Pickup address of system state var
|
||||
LDR r2, [r3, #0] ; Pickup system state
|
||||
ADD r2, r2, #1 ; Increment the interrupt counter
|
||||
STR r2, [r3, #0] ; Store it back in the variable
|
||||
;
|
||||
; /* Now pickup and store all the fault related information. */
|
||||
;
|
||||
; Pickup the memory fault info struct
|
||||
LDR r3, =_txm_module_manager_memory_fault_info
|
||||
LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address
|
||||
LDR r1, [r0] ; Pickup the current thread pointer
|
||||
STR r1, [r3, #0] ; Save current thread pointer
|
||||
|
||||
MRC p15, 0, r0, c6, c0, 0 ; Read DFAR
|
||||
STR r0, [r3, #8] ; Save DFAR
|
||||
|
||||
CMP r0, #0 ; Was it a data or instruction fault?
|
||||
SUBEQ lr, lr, #4 ; Adjust point of exception for instruction
|
||||
SUBNE lr, lr, #8 ; Adjust point of exception for data
|
||||
STR lr, [r3, #4] ; Save point of fault
|
||||
|
||||
MRC p15, 0, r0, c5, c0, 0 ; Read DFSR
|
||||
STR r0, [r3, #12] ; Save DFSR
|
||||
MRC p15, 0, r0, c6, c0, 2 ; Read IFAR
|
||||
STR r0, [r3, #16] ; Save IFAR
|
||||
MRC p15, 0, r0, c5, c0, 1 ; Read IFSR
|
||||
STR r0, [r3, #20] ; Save IFSR
|
||||
MOV r0, #0 ; Build zero register
|
||||
MCR p15, 0, r0, c6, c0, 0 ; Clear DFAR
|
||||
MCR p15, 0, r0, c5, c0, 0 ; Clear DFSR
|
||||
MCR p15, 0, r0, c6, c0, 2 ; Clear IFAR
|
||||
MCR p15, 0, r0, c5, c0, 1 ; Clear IFSR
|
||||
|
||||
; Save registers r0-r12
|
||||
POP {r0-r2}
|
||||
STR r0, [r3, #28] ; Save r0
|
||||
STR r1, [r3, #32] ; Save r1
|
||||
STR r2, [r3, #36] ; Save r2
|
||||
POP {r0}
|
||||
STR r0, [r3, #40] ; Save r3
|
||||
STR r4, [r3, #44] ; Save r4
|
||||
STR r5, [r3, #48] ; Save r5
|
||||
STR r6, [r3, #52] ; Save r6
|
||||
STR r7, [r3, #56] ; Save r7
|
||||
STR r8, [r3, #60] ; Save r8
|
||||
STR r9, [r3, #64] ; Save r9
|
||||
STR r10,[r3, #68] ; Save r10
|
||||
STR r11,[r3, #72] ; Save r11
|
||||
STR r12,[r3, #76] ; Save r12
|
||||
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
MOV r0, lr ; Pickup lr
|
||||
MOV r1, sp ; Pickup sp
|
||||
CPS #ABT_MODE ; Back to ABT mode
|
||||
STR r0, [r3, #80] ; Save lr
|
||||
STR r1, [r3, #24] ; Save sp
|
||||
MRS r0, SPSR ; Pickup SPSR
|
||||
STR r0, [r3, #84] ; Save SPSR
|
||||
ORR r0, r0, #SYS_MODE ; Return into SYS mode
|
||||
BIC r0, r0, #THUMB_MASK ; Clear THUMB mode
|
||||
MSR SPSR_c, r0 ; Save SPSR
|
||||
|
||||
; Call memory manager fault handler
|
||||
BL _txm_module_manager_memory_fault_handler
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the thread exit function to indicate the thread is no longer executing. */
|
||||
;
|
||||
BL _tx_execution_thread_exit ; Call the thread exit function
|
||||
#endif
|
||||
|
||||
LDR r0, =_tx_thread_system_state ; Pickup address of system state
|
||||
LDR r1, [r0] ; Pickup system state
|
||||
SUB r1, r1, #1 ; Decrement
|
||||
STR r1, [r0] ; Store new system state
|
||||
|
||||
MOV r1, #0 ; Build NULL value
|
||||
LDR r0, =_tx_thread_current_ptr ; Pickup address of current thread pointer
|
||||
STR r1, [r0] ; Clear current thread pointer
|
||||
|
||||
; Return from exception
|
||||
LDR lr, =_tx_thread_schedule ; Load scheduler address
|
||||
MOVS pc, lr ; Return to scheduler
|
||||
; *******************************************************************
|
||||
; End of MMU exception handling.
|
||||
; *******************************************************************
|
||||
;
|
||||
BUILD_OPTIONS
|
||||
DC32 _tx_build_options ; Reference to ensure it comes in
|
||||
VERSION_ID
|
||||
DC32 _tx_version_id ; Reference to ensure it comes in
|
||||
END
|
||||
|
||||
2477
ports_module/cortex_r4/iar/example_build/txm.ewp
Normal file
2477
ports_module/cortex_r4/iar/example_build/txm.ewp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
SECTION .text:CODE
|
||||
|
||||
AAPCS INTERWORK, ROPI, RWPI_COMPATIBLE, VFP_COMPATIBLE
|
||||
PRESERVE8
|
||||
|
||||
/* Define public symbols. */
|
||||
|
||||
PUBLIC __txm_module_preamble
|
||||
|
||||
|
||||
/* Define application-specific start/stop entry points for the module. */
|
||||
|
||||
EXTERN demo_module_start
|
||||
|
||||
|
||||
/* Define common external refrences. */
|
||||
|
||||
EXTERN _txm_module_thread_shell_entry
|
||||
EXTERN _txm_module_callback_request_thread_entry
|
||||
EXTERN ROPI$$Length
|
||||
EXTERN RWPI$$Length
|
||||
|
||||
DATA
|
||||
__txm_module_preamble:
|
||||
DC32 0x4D4F4455 ; Module ID
|
||||
DC32 0x6 ; Module Major Version
|
||||
DC32 0x1 ; Module Minor Version
|
||||
DC32 32 ; Module Preamble Size in 32-bit words
|
||||
DC32 0x12345678 ; Module ID (application defined)
|
||||
DC32 0x00000001 ; Module Properties where:
|
||||
; Bits 31-24: Compiler ID
|
||||
; 0 -> IAR
|
||||
; 1 -> RVDS
|
||||
; 2 -> GNU
|
||||
; Bits 23-1: Reserved
|
||||
; Bit 0: 0 -> Privileged mode execution (no MPU protection)
|
||||
; 1 -> User mode execution (MPU protection)
|
||||
DC32 _txm_module_thread_shell_entry - . - 0 ; Module Shell Entry Point
|
||||
DC32 demo_module_start - . - 0 ; Module Start Thread Entry Point
|
||||
DC32 0 ; Module Stop Thread Entry Point
|
||||
DC32 1 ; Module Start/Stop Thread Priority
|
||||
DC32 1022 ; Module Start/Stop Thread Stack Size
|
||||
DC32 _txm_module_callback_request_thread_entry - . - 0 ; Module Callback Thread Entry
|
||||
DC32 1 ; Module Callback Thread Priority
|
||||
DC32 1022 ; Module Callback Thread Stack Size
|
||||
DC32 ROPI$$Length ; Module Code Size
|
||||
DC32 RWPI$$Length ; Module Data Size
|
||||
DC32 0 ; Reserved 0
|
||||
DC32 0 ; Reserved 1
|
||||
DC32 0 ; Reserved 2
|
||||
DC32 0 ; Reserved 3
|
||||
DC32 0 ; Reserved 4
|
||||
DC32 0 ; Reserved 5
|
||||
DC32 0 ; Reserved 6
|
||||
DC32 0 ; Reserved 7
|
||||
DC32 0 ; Reserved 8
|
||||
DC32 0 ; Reserved 9
|
||||
DC32 0 ; Reserved 10
|
||||
DC32 0 ; Reserved 11
|
||||
DC32 0 ; Reserved 12
|
||||
DC32 0 ; Reserved 13
|
||||
DC32 0 ; Reserved 14
|
||||
DC32 0 ; Reserved 15
|
||||
|
||||
END
|
||||
|
||||
|
||||
411
ports_module/cortex_r4/iar/inc/tx_port.h
Normal file
411
ports_module/cortex_r4/iar/inc/tx_port.h
Normal file
@@ -0,0 +1,411 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Port Specific */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* PORT SPECIFIC C INFORMATION RELEASE */
|
||||
/* */
|
||||
/* tx_port.h Cortex-R4/IAR */
|
||||
/* 6.1.6 */
|
||||
/* */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This file contains data type definitions that make the ThreadX */
|
||||
/* real-time kernel function identically on a variety of different */
|
||||
/* processor architectures. For example, the size or number of bits */
|
||||
/* in an "int" data type vary between microprocessor architectures and */
|
||||
/* even C compilers for the same microprocessor. ThreadX does not */
|
||||
/* directly use native C data types. Instead, ThreadX creates its */
|
||||
/* own special types that can be mapped to actual data types by this */
|
||||
/* file to guarantee consistency in the interface and functionality. */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
/* 04-02-2021 Bhupendra Naphade Modified comment(s),updated */
|
||||
/* macro definition, */
|
||||
/* resulting in version 6.1.6 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TX_PORT_H
|
||||
#define TX_PORT_H
|
||||
|
||||
|
||||
/* Determine if the optional ThreadX user define file should be used. */
|
||||
|
||||
#ifdef TX_INCLUDE_USER_DEFINE_FILE
|
||||
|
||||
|
||||
/* Yes, include the user defines in tx_user.h. The defines in this file may
|
||||
alternately be defined on the command line. */
|
||||
|
||||
#include "tx_user.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Define compiler library include files. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <intrinsics.h>
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#include <yvals.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Define ThreadX basic types for this port. */
|
||||
|
||||
#define VOID void
|
||||
typedef char CHAR;
|
||||
typedef unsigned char UCHAR;
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
typedef long LONG;
|
||||
typedef unsigned long ULONG;
|
||||
typedef short SHORT;
|
||||
typedef unsigned short USHORT;
|
||||
|
||||
|
||||
/* Define the priority levels for ThreadX. Legal values range
|
||||
from 32 to 1024 and MUST be evenly divisible by 32. */
|
||||
|
||||
#ifndef TX_MAX_PRIORITIES
|
||||
#define TX_MAX_PRIORITIES 32
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during
|
||||
thread creation is less than this value, the thread create call will return an error. */
|
||||
|
||||
#ifndef TX_MINIMUM_STACK
|
||||
#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the system timer thread's default stack size and priority. These are only applicable
|
||||
if TX_TIMER_PROCESS_IN_ISR is not defined. */
|
||||
|
||||
#ifndef TX_TIMER_THREAD_STACK_SIZE
|
||||
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
|
||||
#endif
|
||||
|
||||
#ifndef TX_TIMER_THREAD_PRIORITY
|
||||
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
|
||||
#endif
|
||||
|
||||
|
||||
/* Define various constants for the ThreadX ARM port. */
|
||||
|
||||
#define TX_INT_DISABLE 0x80 /* Disable IRQ interrupts */
|
||||
#define TX_INT_ENABLE 0x00 /* Enable IRQ interrupts */
|
||||
|
||||
|
||||
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
|
||||
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
|
||||
source constants would be:
|
||||
|
||||
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
|
||||
#define TX_TRACE_TIME_MASK 0x0000FFFFUL
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TX_MISRA_ENABLE
|
||||
#ifndef TX_TRACE_TIME_SOURCE
|
||||
#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time
|
||||
#endif
|
||||
#else
|
||||
ULONG _tx_misra_time_stamp_get(VOID);
|
||||
#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get()
|
||||
#endif
|
||||
|
||||
#ifndef TX_TRACE_TIME_MASK
|
||||
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the port specific options for the _tx_build_options variable. This variable indicates
|
||||
how the ThreadX library was built. */
|
||||
|
||||
#ifdef TX_ENABLE_IRQ_NESTING
|
||||
#define TX_IRQ_NESTING_ENABLED 1
|
||||
#else
|
||||
#define TX_IRQ_NESTING_ENABLED 0
|
||||
#endif
|
||||
|
||||
#define TX_PORT_SPECIFIC_BUILD_OPTIONS (TX_IRQ_NESTING_ENABLED)
|
||||
|
||||
|
||||
/* Define the in-line initialization constant so that modules with in-line
|
||||
initialization capabilities can prevent their initialization from being
|
||||
a function call. */
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
#define TX_DISABLE_INLINE
|
||||
#else
|
||||
#define TX_INLINE_INITIALIZATION
|
||||
#endif
|
||||
|
||||
|
||||
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
|
||||
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
|
||||
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
|
||||
define is negated, thereby forcing the stack fill which is necessary for the stack checking
|
||||
logic. */
|
||||
|
||||
#ifndef TX_MISRA_ENABLE
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
#undef TX_DISABLE_STACK_FILLING
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the TX_THREAD control block extensions for this port. The main reason
|
||||
for the multiple macros is so that backward compatibility can be maintained with
|
||||
existing ThreadX kernel awareness modules. */
|
||||
|
||||
#define TX_THREAD_EXTENSION_0
|
||||
#define TX_THREAD_EXTENSION_1
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable; \
|
||||
VOID *tx_thread_module_instance_ptr; \
|
||||
VOID *tx_thread_module_entry_info_ptr; \
|
||||
ULONG tx_thread_module_current_user_mode; \
|
||||
ULONG tx_thread_module_user_mode; \
|
||||
VOID *tx_thread_module_kernel_stack_start; \
|
||||
VOID *tx_thread_module_kernel_stack_end; \
|
||||
ULONG tx_thread_module_kernel_stack_size; \
|
||||
VOID *tx_thread_module_stack_ptr; \
|
||||
VOID *tx_thread_module_stack_start; \
|
||||
VOID *tx_thread_module_stack_end; \
|
||||
ULONG tx_thread_module_stack_size; \
|
||||
VOID *tx_thread_module_reserved; \
|
||||
VOID *tx_thread_iar_tls_pointer;
|
||||
#else
|
||||
#define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable; \
|
||||
VOID *tx_thread_module_instance_ptr; \
|
||||
VOID *tx_thread_module_entry_info_ptr; \
|
||||
ULONG tx_thread_module_current_user_mode; \
|
||||
ULONG tx_thread_module_user_mode; \
|
||||
VOID *tx_thread_module_kernel_stack_start; \
|
||||
VOID *tx_thread_module_kernel_stack_end; \
|
||||
ULONG tx_thread_module_kernel_stack_size; \
|
||||
VOID *tx_thread_module_stack_ptr; \
|
||||
VOID *tx_thread_module_stack_start; \
|
||||
VOID *tx_thread_module_stack_end; \
|
||||
ULONG tx_thread_module_stack_size; \
|
||||
VOID *tx_thread_module_reserved;
|
||||
#endif
|
||||
#define TX_THREAD_EXTENSION_3
|
||||
|
||||
|
||||
/* Define the port extensions of the remaining ThreadX objects. */
|
||||
|
||||
#define TX_BLOCK_POOL_EXTENSION
|
||||
#define TX_BYTE_POOL_EXTENSION
|
||||
#define TX_EVENT_FLAGS_GROUP_EXTENSION VOID *tx_event_flags_group_module_instance; \
|
||||
VOID (*tx_event_flags_group_set_module_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *group_ptr);
|
||||
#define TX_MUTEX_EXTENSION
|
||||
#define TX_QUEUE_EXTENSION VOID *tx_queue_module_instance; \
|
||||
VOID (*tx_queue_send_module_notify)(struct TX_QUEUE_STRUCT *queue_ptr);
|
||||
#define TX_SEMAPHORE_EXTENSION VOID *tx_semaphore_module_instance; \
|
||||
VOID (*tx_semaphore_put_module_notify)(struct TX_SEMAPHORE_STRUCT *semaphore_ptr);
|
||||
#define TX_TIMER_EXTENSION VOID *tx_timer_module_instance; \
|
||||
VOID (*tx_timer_module_expiration_function)(ULONG id);
|
||||
|
||||
|
||||
/* Define the user extension field of the thread control block. Nothing
|
||||
additional is needed for this port so it is defined as white space. */
|
||||
|
||||
#ifndef TX_THREAD_USER_EXTENSION
|
||||
#define TX_THREAD_USER_EXTENSION
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete,
|
||||
tx_thread_shell_entry, and tx_thread_terminate. */
|
||||
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#if (__VER__ < 8000000)
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
|
||||
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL;
|
||||
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0);
|
||||
#else
|
||||
void *_tx_iar_create_per_thread_tls_area(void);
|
||||
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
|
||||
void __iar_Initlocks(void);
|
||||
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area();
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \
|
||||
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0);
|
||||
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0);
|
||||
#endif
|
||||
#else
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
|
||||
#endif
|
||||
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
|
||||
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
|
||||
|
||||
|
||||
/* Define the ThreadX object creation extensions for the remaining objects. */
|
||||
|
||||
#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
|
||||
#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
|
||||
#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
|
||||
#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
|
||||
#define TX_QUEUE_CREATE_EXTENSION(queue_ptr)
|
||||
#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
|
||||
#define TX_TIMER_CREATE_EXTENSION(timer_ptr)
|
||||
|
||||
|
||||
/* Define the ThreadX object deletion extensions for the remaining objects. */
|
||||
|
||||
#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
|
||||
#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
|
||||
#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
|
||||
#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
|
||||
#define TX_QUEUE_DELETE_EXTENSION(queue_ptr)
|
||||
#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
|
||||
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
|
||||
|
||||
|
||||
/* Determine if the ARM architecture has the CLZ instruction. This is available on
|
||||
architectures v5 and above. If available, redefine the macro for calculating the
|
||||
lowest bit set. */
|
||||
|
||||
#ifndef TX_DISABLE_INLINE
|
||||
|
||||
#if __CORE__ > __ARM4TM__
|
||||
|
||||
#if __CPU_MODE__ == 2
|
||||
|
||||
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \
|
||||
b = (UINT) __CLZ(m); \
|
||||
b = 31 - b;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Define ThreadX interrupt lockout and restore macros for protection on
|
||||
access of critical kernel information. The restore interrupt macro must
|
||||
restore the interrupt posture of the running thread prior to the value
|
||||
present prior to the disable macro. In most cases, the save area macro
|
||||
is used to define a local function save area for the disable and restore
|
||||
macros. */
|
||||
|
||||
|
||||
/* First, check and see what mode the file is being compiled in. The IAR compiler
|
||||
defines __CPU_MODE__ to 1, if the Thumb mode is present, and 2 if ARM 32-bit mode
|
||||
is present. If ARM 32-bit mode is present, the fast CPSR manipulation macros
|
||||
are available. Otherwise, if Thumb mode is present, we must use function calls. */
|
||||
|
||||
#ifdef TX_DISABLE_INLINE
|
||||
|
||||
UINT _tx_thread_interrupt_disable(void);
|
||||
void _tx_thread_interrupt_restore(UINT old_posture);
|
||||
|
||||
|
||||
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
|
||||
|
||||
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();
|
||||
#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save);
|
||||
|
||||
#else
|
||||
#if __CPU_MODE__ == 2
|
||||
|
||||
#if (__VER__ < 8002000)
|
||||
__intrinsic unsigned long __get_CPSR();
|
||||
__intrinsic void __set_CPSR( unsigned long );
|
||||
#endif
|
||||
|
||||
|
||||
#if (__VER__ < 8002000)
|
||||
#define TX_INTERRUPT_SAVE_AREA ULONG interrupt_save;
|
||||
#else
|
||||
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
|
||||
#endif
|
||||
|
||||
#define TX_DISABLE interrupt_save = __get_CPSR(); \
|
||||
__set_CPSR(interrupt_save | TX_INT_DISABLE);
|
||||
#define TX_RESTORE __set_CPSR(interrupt_save);
|
||||
|
||||
#else
|
||||
|
||||
UINT _tx_thread_interrupt_disable(void);
|
||||
void _tx_thread_interrupt_restore(UINT old_posture);
|
||||
|
||||
|
||||
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
|
||||
|
||||
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();
|
||||
#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the interrupt lockout macros for each ThreadX object. */
|
||||
|
||||
#define TX_BLOCK_POOL_DISABLE TX_DISABLE
|
||||
#define TX_BYTE_POOL_DISABLE TX_DISABLE
|
||||
#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE
|
||||
#define TX_MUTEX_DISABLE TX_DISABLE
|
||||
#define TX_QUEUE_DISABLE TX_DISABLE
|
||||
#define TX_SEMAPHORE_DISABLE TX_DISABLE
|
||||
|
||||
|
||||
/* Define VFP extension for the Cortex-R4. Each is assumed to be called in the context of the executing
|
||||
thread. */
|
||||
|
||||
void tx_thread_vfp_enable(void);
|
||||
void tx_thread_vfp_disable(void);
|
||||
|
||||
|
||||
/* Define the version ID of ThreadX. This may be utilized by the application. */
|
||||
|
||||
#ifdef TX_THREAD_INIT
|
||||
CHAR _tx_version_id[] =
|
||||
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-R4/IAR Version 6.1.6 *";
|
||||
#else
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
extern CHAR _tx_version_id[100];
|
||||
#else
|
||||
extern CHAR _tx_version_id[];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
347
ports_module/cortex_r4/iar/inc/txm_module_port.h
Normal file
347
ports_module/cortex_r4/iar/inc/txm_module_port.h
Normal file
@@ -0,0 +1,347 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* APPLICATION INTERFACE DEFINITION RELEASE */
|
||||
/* */
|
||||
/* txm_module_port.h Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This file defines the basic module constants, interface structures, */
|
||||
/* and function prototypes. */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TXM_MODULE_PORT_H
|
||||
#define TXM_MODULE_PORT_H
|
||||
|
||||
/* Determine if the optional Modules user define file should be used. */
|
||||
|
||||
#ifdef TXM_MODULE_INCLUDE_USER_DEFINE_FILE
|
||||
|
||||
|
||||
/* Yes, include the user defines in txm_module_user.h. The defines in this file may
|
||||
alternately be defined on the command line. */
|
||||
|
||||
#include "txm_module_user.h"
|
||||
#endif
|
||||
|
||||
/* It is assumed that the base ThreadX tx_port.h file has been modified to add the
|
||||
following extensions to the ThreadX thread control block (this code should replace
|
||||
the corresponding macro define in tx_port.h):
|
||||
|
||||
#define TX_THREAD_EXTENSION_2 ULONG tx_thread_vfp_enable; \
|
||||
VOID *tx_thread_module_instance_ptr; \
|
||||
VOID *tx_thread_module_entry_info_ptr; \
|
||||
ULONG tx_thread_module_current_user_mode; \
|
||||
ULONG tx_thread_module_user_mode; \
|
||||
VOID *tx_thread_module_kernel_stack_start; \
|
||||
VOID *tx_thread_module_kernel_stack_end; \
|
||||
ULONG tx_thread_module_kernel_stack_size; \
|
||||
VOID *tx_thread_module_stack_ptr; \
|
||||
VOID *tx_thread_module_stack_start; \
|
||||
VOID *tx_thread_module_stack_end; \
|
||||
ULONG tx_thread_module_stack_size; \
|
||||
VOID *tx_thread_module_reserved; \
|
||||
VOID *tx_thread_iar_tls_pointer;
|
||||
|
||||
The following extensions must also be defined in tx_port.h:
|
||||
|
||||
#define TX_EVENT_FLAGS_GROUP_EXTENSION VOID *tx_event_flags_group_module_instance; \
|
||||
VOID (*tx_event_flags_group_set_module_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *group_ptr);
|
||||
|
||||
#define TX_QUEUE_EXTENSION VOID *tx_queue_module_instance; \
|
||||
VOID (*tx_queue_send_module_notify)(struct TX_QUEUE_STRUCT *queue_ptr);
|
||||
|
||||
#define TX_SEMAPHORE_EXTENSION VOID *tx_semaphore_module_instance; \
|
||||
VOID (*tx_semaphore_put_module_notify)(struct TX_SEMAPHORE_STRUCT *semaphore_ptr);
|
||||
|
||||
#define TX_TIMER_EXTENSION VOID *tx_timer_module_instance; \
|
||||
VOID (*tx_timer_module_expiration_function)(ULONG id);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/* Define the kernel stack size for a module thread. */
|
||||
#ifndef TXM_MODULE_KERNEL_STACK_SIZE
|
||||
#define TXM_MODULE_KERNEL_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
/* For the following 3 access control settings, change TEX and C, B, S (bits 5 through 0)
|
||||
* to reflect your system memory attributes (cache, shareable, memory type). */
|
||||
/* Code region access control: read-only, outer & inner write-back, normal memory, shareable. */
|
||||
#define TXM_MODULE_MPU_CODE_ACCESS_CONTROL 0x00000607
|
||||
/* Data region access control: execute never, read/write, outer & inner write-back, normal memory, shareable. */
|
||||
#define TXM_MODULE_MPU_DATA_ACCESS_CONTROL 0x00001307
|
||||
/* Shared region access control: execute never, read-only, outer & inner write-back, normal memory, shareable. */
|
||||
#define TXM_MODULE_MPU_SHARED_ACCESS_CONTROL 0x00001207
|
||||
|
||||
/* Define constants specific to the tools the module can be built with for this particular modules port. */
|
||||
|
||||
#define TXM_MODULE_IAR_COMPILER 0x00000000
|
||||
#define TXM_MODULE_RVDS_COMPILER 0x01000000
|
||||
#define TXM_MODULE_GNU_COMPILER 0x02000000
|
||||
#define TXM_MODULE_COMPILER_MASK 0xFF000000
|
||||
#define TXM_MODULE_OPTIONS_MASK 0x000000FF
|
||||
|
||||
|
||||
/* Define the properties for this particular module port. */
|
||||
|
||||
#define TXM_MODULE_MEMORY_PROTECTION_ENABLED
|
||||
|
||||
#ifdef TXM_MODULE_MEMORY_PROTECTION_ENABLED
|
||||
#define TXM_MODULE_REQUIRE_ALLOCATED_OBJECT_MEMORY
|
||||
#else
|
||||
#define TXM_MODULE_REQUIRE_LOCAL_OBJECT_MEMORY
|
||||
#endif
|
||||
|
||||
#define TXM_MODULE_USER_MODE 0x00000001
|
||||
#define TXM_MODULE_MEMORY_PROTECTION 0x00000001
|
||||
|
||||
|
||||
/* Define the supported options for this module. */
|
||||
|
||||
#define TXM_MODULE_MANAGER_SUPPORTED_OPTIONS (TXM_MODULE_MEMORY_PROTECTION)
|
||||
#define TXM_MODULE_MANAGER_REQUIRED_OPTIONS 0
|
||||
|
||||
|
||||
/* Define offset adjustments according to the compiler used to build the module. */
|
||||
|
||||
#define TXM_MODULE_IAR_SHELL_ADJUST 24
|
||||
#define TXM_MODULE_IAR_START_ADJUST 28
|
||||
#define TXM_MODULE_IAR_STOP_ADJUST 32
|
||||
#define TXM_MODULE_IAR_CALLBACK_ADJUST 44
|
||||
|
||||
#define TXM_MODULE_RVDS_SHELL_ADJUST 0
|
||||
#define TXM_MODULE_RVDS_START_ADJUST 0
|
||||
#define TXM_MODULE_RVDS_STOP_ADJUST 0
|
||||
#define TXM_MODULE_RVDS_CALLBACK_ADJUST 0
|
||||
|
||||
#define TXM_MODULE_GNU_SHELL_ADJUST 24
|
||||
#define TXM_MODULE_GNU_START_ADJUST 28
|
||||
#define TXM_MODULE_GNU_STOP_ADJUST 32
|
||||
#define TXM_MODULE_GNU_CALLBACK_ADJUST 44
|
||||
|
||||
|
||||
/* Define other module port-specific constants. */
|
||||
|
||||
|
||||
/* Define INLINE_DECLARE to inline for IAR compiler. */
|
||||
|
||||
#define INLINE_DECLARE inline
|
||||
|
||||
/* Define the number of MPU entries assigned to the code and data sections.
|
||||
On Cortex-R parts, there are 12 total entries. ThreadX uses one for access
|
||||
to the kernel entry function, thus 11 remain for code and data protection. */
|
||||
#define TXM_MODULE_MPU_TOTAL_ENTRIES 12
|
||||
#define TXM_MODULE_MPU_CODE_ENTRIES 4
|
||||
#define TXM_MODULE_MPU_DATA_ENTRIES 4
|
||||
#define TXM_MODULE_MPU_SHARED_ENTRIES 3
|
||||
|
||||
#define TXM_MODULE_MPU_KERNEL_ENTRY_INDEX 0
|
||||
#define TXM_MODULE_MPU_SHARED_INDEX 9
|
||||
|
||||
/* There are 3 registers to set up each MPU region: DRACR, DRBAR, DRSR. */
|
||||
#define TXM_MODULE_MPU_REGISTER_COUNT 3
|
||||
|
||||
#define TXM_ENABLE_REGION 0x01
|
||||
|
||||
/* Shared memory region attributes. */
|
||||
#define TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE 1
|
||||
#define TXM_MODULE_MANAGER_ATTRIBUTE_WRITE_MPU_BIT 0x00000100
|
||||
|
||||
typedef struct TXM_MODULE_MPU_INFO_STRUCT
|
||||
{
|
||||
ULONG txm_module_mpu_region_address;
|
||||
ULONG txm_module_mpu_region_size;
|
||||
ULONG txm_module_mpu_region_attributes;
|
||||
} TXM_MODULE_MPU_INFO;
|
||||
/* Define the port-extensions to the module manager instance structure. */
|
||||
|
||||
#define TXM_MODULE_MANAGER_PORT_EXTENSION \
|
||||
TXM_MODULE_MPU_INFO txm_module_instance_mpu_registers[TXM_MODULE_MPU_TOTAL_ENTRIES]; \
|
||||
ULONG txm_module_instance_shared_memory_count; \
|
||||
ULONG txm_module_instance_shared_memory_address[TXM_MODULE_MPU_SHARED_ENTRIES]; \
|
||||
ULONG txm_module_instance_shared_memory_length[TXM_MODULE_MPU_SHARED_ENTRIES];
|
||||
|
||||
|
||||
/* Define the memory fault information structure that is populated when a memory fault occurs. */
|
||||
|
||||
|
||||
typedef struct TXM_MODULE_MANAGER_MEMORY_FAULT_INFO_STRUCT
|
||||
{
|
||||
TX_THREAD *txm_module_manager_memory_fault_info_thread_ptr;
|
||||
VOID *txm_module_manager_memory_fault_info_code_location;
|
||||
ULONG txm_module_manager_memory_fault_info_dfar;
|
||||
ULONG txm_module_manager_memory_fault_info_dfsr;
|
||||
ULONG txm_module_manager_memory_fault_info_ifar;
|
||||
ULONG txm_module_manager_memory_fault_info_ifsr;
|
||||
ULONG txm_module_manager_memory_fault_info_sp;
|
||||
ULONG txm_module_manager_memory_fault_info_r0;
|
||||
ULONG txm_module_manager_memory_fault_info_r1;
|
||||
ULONG txm_module_manager_memory_fault_info_r2;
|
||||
ULONG txm_module_manager_memory_fault_info_r3;
|
||||
ULONG txm_module_manager_memory_fault_info_r4;
|
||||
ULONG txm_module_manager_memory_fault_info_r5;
|
||||
ULONG txm_module_manager_memory_fault_info_r6;
|
||||
ULONG txm_module_manager_memory_fault_info_r7;
|
||||
ULONG txm_module_manager_memory_fault_info_r8;
|
||||
ULONG txm_module_manager_memory_fault_info_r9;
|
||||
ULONG txm_module_manager_memory_fault_info_r10;
|
||||
ULONG txm_module_manager_memory_fault_info_r11;
|
||||
ULONG txm_module_manager_memory_fault_info_r12;
|
||||
ULONG txm_module_manager_memory_fault_info_lr;
|
||||
ULONG txm_module_manager_memory_fault_info_cpsr;
|
||||
} TXM_MODULE_MANAGER_MEMORY_FAULT_INFO;
|
||||
|
||||
|
||||
#define TXM_MODULE_MANAGER_FAULT_INFO \
|
||||
TXM_MODULE_MANAGER_MEMORY_FAULT_INFO _txm_module_manager_memory_fault_info;
|
||||
|
||||
/* Define the macro to check the stack available in dispatch. */
|
||||
#define TXM_MODULE_MANAGER_CHECK_STACK_AVAILABLE
|
||||
|
||||
|
||||
/* Define the macro to check the code alignment. */
|
||||
|
||||
#define TXM_MODULE_MANAGER_CHECK_CODE_ALIGNMENT(module_location, code_alignment) \
|
||||
{ \
|
||||
ULONG temp; \
|
||||
temp = (ULONG) module_location; \
|
||||
temp = temp & (code_alignment - 1); \
|
||||
if (temp) \
|
||||
{ \
|
||||
_tx_mutex_put(&_txm_module_manager_mutex); \
|
||||
return(TXM_MODULE_ALIGNMENT_ERROR); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* Define the macro to adjust the alignment and size for code/data areas. */
|
||||
|
||||
#define TXM_MODULE_MANAGER_ALIGNMENT_ADJUST(module_preamble, code_size, code_alignment, data_size, data_alignment) _txm_module_manager_alignment_adjust(module_preamble, &code_size, &code_alignment, &data_size, &data_alignment);
|
||||
|
||||
|
||||
/* Define the macro to adjust the symbols in the module preamble. */
|
||||
|
||||
#define TXM_MODULE_MANAGER_CALCULATE_ADJUSTMENTS(properties, shell_function_adjust, start_function_adjust, stop_function_adjust, callback_function_adjust) \
|
||||
if ((properties & TXM_MODULE_COMPILER_MASK) == TXM_MODULE_IAR_COMPILER) \
|
||||
{ \
|
||||
shell_function_adjust = TXM_MODULE_IAR_SHELL_ADJUST; \
|
||||
start_function_adjust = TXM_MODULE_IAR_START_ADJUST; \
|
||||
stop_function_adjust = TXM_MODULE_IAR_STOP_ADJUST; \
|
||||
callback_function_adjust = TXM_MODULE_IAR_CALLBACK_ADJUST; \
|
||||
} \
|
||||
else if ((properties & TXM_MODULE_COMPILER_MASK) == TXM_MODULE_RVDS_COMPILER) \
|
||||
{ \
|
||||
shell_function_adjust = TXM_MODULE_RVDS_SHELL_ADJUST; \
|
||||
start_function_adjust = TXM_MODULE_RVDS_START_ADJUST; \
|
||||
stop_function_adjust = TXM_MODULE_RVDS_STOP_ADJUST; \
|
||||
callback_function_adjust = TXM_MODULE_RVDS_CALLBACK_ADJUST; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
shell_function_adjust = TXM_MODULE_GNU_SHELL_ADJUST; \
|
||||
start_function_adjust = TXM_MODULE_GNU_START_ADJUST; \
|
||||
stop_function_adjust = TXM_MODULE_GNU_STOP_ADJUST; \
|
||||
callback_function_adjust = TXM_MODULE_GNU_CALLBACK_ADJUST; \
|
||||
}
|
||||
|
||||
|
||||
/* Define the macro to populate the thread control block with module port-specific information.
|
||||
Check if the module is in user mode and set up txm_module_thread_entry_info_kernel_call_dispatcher accordingly.
|
||||
*/
|
||||
|
||||
#define TXM_MODULE_MANAGER_THREAD_SETUP(thread_ptr, module_instance) \
|
||||
thread_ptr -> tx_thread_module_current_user_mode = module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION; \
|
||||
thread_ptr -> tx_thread_module_user_mode = module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION; \
|
||||
if (thread_ptr -> tx_thread_module_user_mode) \
|
||||
{ \
|
||||
thread_entry_info -> txm_module_thread_entry_info_kernel_call_dispatcher = _txm_module_manager_user_mode_entry; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
thread_entry_info -> txm_module_thread_entry_info_kernel_call_dispatcher = _txm_module_manager_kernel_dispatch; \
|
||||
}
|
||||
|
||||
|
||||
/* Define the macro to populate the module control block with module port-specific information.
|
||||
If memory protection is enabled, set up the MPU registers.
|
||||
*/
|
||||
#define TXM_MODULE_MANAGER_MODULE_SETUP(module_instance) \
|
||||
if (module_instance -> txm_module_instance_property_flags & TXM_MODULE_MEMORY_PROTECTION) \
|
||||
{ \
|
||||
_txm_module_manager_mm_register_setup(module_instance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* Do nothing. */ \
|
||||
}
|
||||
|
||||
/* Define the macro to perform port-specific functions when unloading the module. */
|
||||
/* Nothing needs to be done for this port. */
|
||||
#define TXM_MODULE_MANAGER_MODULE_UNLOAD(module_instance)
|
||||
|
||||
|
||||
/* Define the macros to perform port-specific checks when passing pointers to the kernel. */
|
||||
|
||||
/* Define macro to make sure object is inside the module's data. */
|
||||
#define TXM_MODULE_MANAGER_CHECK_INSIDE_DATA(module_instance, obj_ptr, obj_size) \
|
||||
_txm_module_manager_inside_data_check(module_instance, obj_ptr, obj_size)
|
||||
|
||||
/* Define some internal prototypes to this module port. */
|
||||
|
||||
#ifndef TX_SOURCE_CODE
|
||||
#define txm_module_manager_memory_fault_notify _txm_module_manager_memory_fault_notify
|
||||
#endif
|
||||
|
||||
|
||||
#define TXM_MODULE_MANAGER_ADDITIONAL_PROTOTYPES \
|
||||
VOID _txm_module_manager_alignment_adjust(TXM_MODULE_PREAMBLE *module_preamble, ULONG *code_size, ULONG *code_alignment, ULONG *data_size, ULONG *data_alignment); \
|
||||
ULONG _txm_module_manager_data_pointer_check(TXM_MODULE_INSTANCE *module_instance, ULONG pointer); \
|
||||
VOID _txm_module_manager_memory_fault_handler(VOID); \
|
||||
UINT _txm_module_manager_memory_fault_notify(VOID (*notify_function)(TX_THREAD *, TXM_MODULE_INSTANCE *)); \
|
||||
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance); \
|
||||
ULONG _txm_power_of_two_block_size(ULONG size); \
|
||||
ULONG _txm_module_manager_calculate_srd_bits(ULONG block_size, ULONG length); \
|
||||
ULONG _txm_module_manager_region_size_get(ULONG block_size); \
|
||||
UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ULONG obj_ptr, UINT obj_size);
|
||||
|
||||
#define TXM_MODULE_MANAGER_VERSION_ID \
|
||||
CHAR _txm_module_manager_version_id[] = \
|
||||
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Module Cortex-R4/MPU/IAR Version 6.1 *";
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef TXM_MODULE
|
||||
#define TXM_MODULE
|
||||
#endif
|
||||
|
||||
#ifndef TX_SOURCE_CODE
|
||||
#define TX_SOURCE_CODE
|
||||
#endif
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "txm_module.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
/* Define the global module entry pointer from the start thread of the module. */
|
||||
|
||||
TXM_MODULE_THREAD_ENTRY_INFO *_txm_module_entry_info;
|
||||
|
||||
|
||||
/* Define the dispatch function pointer used in the module implementation. */
|
||||
|
||||
ULONG (*_txm_module_kernel_call_dispatcher)(ULONG kernel_request, ULONG param_1, ULONG param_2, ULONG param3);
|
||||
|
||||
|
||||
/* Define the IAR startup code that clears the uninitialized global data and sets up the
|
||||
preset global variables. */
|
||||
|
||||
extern VOID __iar_data_init3(VOID);
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_thread_shell_entry Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function calls the specified entry function of the thread. It */
|
||||
/* also provides a place for the thread's entry function to return. */
|
||||
/* If the thread returns, this function places the thread in a */
|
||||
/* "COMPLETED" state. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to current thread */
|
||||
/* thread_info Pointer to thread entry info */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* __iar_data_init3 IAR global initialization function*/
|
||||
/* thread_entry Thread's entry function */
|
||||
/* tx_thread_resume Resume the module callback thread */
|
||||
/* _txm_module_thread_system_suspend Module thread suspension routine */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Initial thread stack frame */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _txm_module_thread_shell_entry(TX_THREAD *thread_ptr, TXM_MODULE_THREAD_ENTRY_INFO *thread_info)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*entry_exit_notify)(TX_THREAD *, UINT);
|
||||
#endif
|
||||
|
||||
|
||||
/* Determine if this is the start thread. If so, we must prepare the module for
|
||||
execution. If not, simply skip the C startup code. */
|
||||
if (thread_info -> txm_module_thread_entry_info_start_thread)
|
||||
{
|
||||
/* Initialize the IAR C environment. */
|
||||
__iar_data_init3();
|
||||
|
||||
/* Save the entry info pointer, for later use. */
|
||||
_txm_module_entry_info = thread_info;
|
||||
|
||||
/* Save the kernel function dispatch address. This is used to make all resident calls from
|
||||
the module. */
|
||||
_txm_module_kernel_call_dispatcher = thread_info -> txm_module_thread_entry_info_kernel_call_dispatcher;
|
||||
|
||||
/* Ensure that we have a valid pointer. */
|
||||
while (!_txm_module_kernel_call_dispatcher)
|
||||
{
|
||||
/* Loop here, if an error is present getting the dispatch function pointer!
|
||||
An error here typically indicates the resident portion of _tx_thread_schedule
|
||||
is not supporting the trap to obtain the function pointer. */
|
||||
}
|
||||
|
||||
/* Resume the module's callback thread, already created in the manager. */
|
||||
_txe_thread_resume(thread_info -> txm_module_thread_entry_info_callback_request_thread);
|
||||
}
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the entry/exit application callback routine. */
|
||||
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
|
||||
|
||||
/* Determine if an application callback routine is specified. */
|
||||
if (entry_exit_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, notify application that this thread has been entered! */
|
||||
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call current thread's entry function. */
|
||||
(thread_info -> txm_module_thread_entry_info_entry) (thread_info -> txm_module_thread_entry_info_parameter);
|
||||
|
||||
/* Suspend thread with a "completed" state. */
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the entry/exit application callback routine again. */
|
||||
entry_exit_notify = thread_info -> txm_module_thread_entry_info_exit_notify;
|
||||
|
||||
/* Determine if an application callback routine is specified. */
|
||||
if (entry_exit_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, notify application that this thread has exited! */
|
||||
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_txm_module_thread_system_suspend(thread_ptr);
|
||||
|
||||
#ifdef TX_SAFETY_CRITICAL
|
||||
|
||||
/* If we ever get here, raise safety critical exception. */
|
||||
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
804
ports_module/cortex_r4/iar/module_manager/src/tx_iar.c
Normal file
804
ports_module/cortex_r4/iar/module_manager/src/tx_iar.c
Normal file
@@ -0,0 +1,804 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** IAR Multithreaded Library Support */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Define IAR library for tools prior to version 8. */
|
||||
|
||||
#if (__VER__ < 8000000)
|
||||
|
||||
|
||||
/* IAR version 7 and below. */
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/* This implementation requires that the following macros are defined in the
|
||||
tx_port.h file and <yvals.h> is included with the following code segments:
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#include <yvals.h>
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer;
|
||||
#else
|
||||
#define TX_THREAD_EXTENSION_2
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
|
||||
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL;
|
||||
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0);
|
||||
#else
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
|
||||
#endif
|
||||
|
||||
This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the
|
||||
application.
|
||||
|
||||
Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected.
|
||||
*/
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
|
||||
#include <yvals.h>
|
||||
|
||||
|
||||
#if _MULTI_THREAD
|
||||
|
||||
TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK];
|
||||
UINT __tx_iar_system_lock_next_free_mutex = 0;
|
||||
|
||||
|
||||
/* Define error counters, just for debug purposes. */
|
||||
|
||||
UINT __tx_iar_system_lock_no_mutexes;
|
||||
UINT __tx_iar_system_lock_internal_errors;
|
||||
UINT __tx_iar_system_lock_isr_caller;
|
||||
|
||||
|
||||
/* Define the TLS access function for the IAR library. */
|
||||
|
||||
void _DLIB_TLS_MEMORY *__iar_dlib_perthread_access(void _DLIB_TLS_MEMORY *symbp)
|
||||
{
|
||||
|
||||
char _DLIB_TLS_MEMORY *p = 0;
|
||||
|
||||
/* Is there a current thread? */
|
||||
if (_tx_thread_current_ptr)
|
||||
p = (char _DLIB_TLS_MEMORY *) _tx_thread_current_ptr -> tx_thread_iar_tls_pointer;
|
||||
else
|
||||
p = (void _DLIB_TLS_MEMORY *) __segment_begin("__DLIB_PERTHREAD");
|
||||
p += __IAR_DLIB_PERTHREAD_SYMBOL_OFFSET(symbp);
|
||||
return (void _DLIB_TLS_MEMORY *) p;
|
||||
}
|
||||
|
||||
|
||||
/* Define mutexes for IAR library. */
|
||||
|
||||
void __iar_system_Mtxinit(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT i;
|
||||
UINT status;
|
||||
TX_MUTEX *mutex_ptr;
|
||||
|
||||
|
||||
/* First, find a free mutex in the list. */
|
||||
for (i = 0; i < _MAX_LOCK; i++)
|
||||
{
|
||||
|
||||
/* Setup a pointer to the start of the next free mutex. */
|
||||
mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++];
|
||||
|
||||
/* Check for wrap-around on the next free mutex. */
|
||||
if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Yes, set the free index back to 0. */
|
||||
__tx_iar_system_lock_next_free_mutex = 0;
|
||||
}
|
||||
|
||||
/* Is this mutex free? */
|
||||
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Yes, this mutex is free, get out of the loop! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if a free mutex was found. */
|
||||
if (i >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Error! No more free mutexes! */
|
||||
|
||||
/* Increment the no mutexes error counter. */
|
||||
__tx_iar_system_lock_no_mutexes++;
|
||||
|
||||
/* Set return pointer to NULL. */
|
||||
*m = TX_NULL;
|
||||
|
||||
/* Return. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now create the ThreadX mutex for the IAR library. */
|
||||
status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT);
|
||||
|
||||
/* Determine if the creation was successful. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Yes, successful creation, return mutex pointer. */
|
||||
*m = (VOID *) mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the internal error counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
|
||||
/* Return a NULL pointer to indicate an error. */
|
||||
*m = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_system_Mtxdst(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
/* Simply delete the mutex. */
|
||||
_tx_mutex_delete((TX_MUTEX *) *m);
|
||||
}
|
||||
|
||||
void __iar_system_Mtxlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex locks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Get the mutex. */
|
||||
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_system_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_system_Mtxunlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex unlocks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Release the mutex. */
|
||||
status = _tx_mutex_put((TX_MUTEX *) *m);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_system_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if _DLIB_FILE_DESCRIPTOR
|
||||
|
||||
TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK];
|
||||
UINT __tx_iar_file_lock_next_free_mutex = 0;
|
||||
|
||||
|
||||
/* Define error counters, just for debug purposes. */
|
||||
|
||||
UINT __tx_iar_file_lock_no_mutexes;
|
||||
UINT __tx_iar_file_lock_internal_errors;
|
||||
UINT __tx_iar_file_lock_isr_caller;
|
||||
|
||||
|
||||
void __iar_file_Mtxinit(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT i;
|
||||
UINT status;
|
||||
TX_MUTEX *mutex_ptr;
|
||||
|
||||
|
||||
/* First, find a free mutex in the list. */
|
||||
for (i = 0; i < _MAX_FLOCK; i++)
|
||||
{
|
||||
|
||||
/* Setup a pointer to the start of the next free mutex. */
|
||||
mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++];
|
||||
|
||||
/* Check for wrap-around on the next free mutex. */
|
||||
if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Yes, set the free index back to 0. */
|
||||
__tx_iar_file_lock_next_free_mutex = 0;
|
||||
}
|
||||
|
||||
/* Is this mutex free? */
|
||||
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Yes, this mutex is free, get out of the loop! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if a free mutex was found. */
|
||||
if (i >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Error! No more free mutexes! */
|
||||
|
||||
/* Increment the no mutexes error counter. */
|
||||
__tx_iar_file_lock_no_mutexes++;
|
||||
|
||||
/* Set return pointer to NULL. */
|
||||
*m = TX_NULL;
|
||||
|
||||
/* Return. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now create the ThreadX mutex for the IAR library. */
|
||||
status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT);
|
||||
|
||||
/* Determine if the creation was successful. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Yes, successful creation, return mutex pointer. */
|
||||
*m = (VOID *) mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the internal error counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
|
||||
/* Return a NULL pointer to indicate an error. */
|
||||
*m = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_file_Mtxdst(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
/* Simply delete the mutex. */
|
||||
_tx_mutex_delete((TX_MUTEX *) *m);
|
||||
}
|
||||
|
||||
void __iar_file_Mtxlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex locks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Get the mutex. */
|
||||
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_file_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_file_Mtxunlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex unlocks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Release the mutex. */
|
||||
status = _tx_mutex_put((TX_MUTEX *) *m);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_file_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
#endif /* _DLIB_FILE_DESCRIPTOR */
|
||||
|
||||
#endif /* _MULTI_THREAD */
|
||||
|
||||
#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */
|
||||
|
||||
#else /* IAR version 8 and above. */
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
/* This implementation requires that the following macros are defined in the
|
||||
tx_port.h file and <yvals.h> is included with the following code segments:
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#include <yvals.h>
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer;
|
||||
#else
|
||||
#define TX_THREAD_EXTENSION_2
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
void *_tx_iar_create_per_thread_tls_area(void);
|
||||
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
|
||||
void __iar_Initlocks(void);
|
||||
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {__iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
|
||||
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0);
|
||||
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0);
|
||||
#else
|
||||
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
|
||||
#endif
|
||||
|
||||
This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the
|
||||
application.
|
||||
|
||||
Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected.
|
||||
*/
|
||||
|
||||
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
|
||||
|
||||
#include <DLib_threads.h>
|
||||
|
||||
|
||||
void * __aeabi_read_tp();
|
||||
|
||||
void* _tx_iar_create_per_thread_tls_area();
|
||||
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
|
||||
|
||||
#pragma section="__iar_tls$$DATA"
|
||||
|
||||
/* Define the TLS access function for the IAR library. */
|
||||
void * __aeabi_read_tp(void)
|
||||
{
|
||||
void *p = 0;
|
||||
TX_THREAD *thread_ptr = _tx_thread_current_ptr;
|
||||
if (thread_ptr)
|
||||
{
|
||||
p = thread_ptr->tx_thread_iar_tls_pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = __section_begin("__iar_tls$$DATA");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Define the TLS creation and destruction to use malloc/free. */
|
||||
|
||||
void* _tx_iar_create_per_thread_tls_area()
|
||||
{
|
||||
UINT tls_size = __iar_tls_size();
|
||||
|
||||
/* Get memory for TLS. */
|
||||
void *p = malloc(tls_size);
|
||||
|
||||
/* Initialize TLS-area and run constructors for objects in TLS */
|
||||
__iar_tls_init(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr)
|
||||
{
|
||||
/* Destroy objects living in TLS */
|
||||
__call_thread_dtors();
|
||||
free(tls_ptr);
|
||||
}
|
||||
|
||||
#ifndef _MAX_LOCK
|
||||
#define _MAX_LOCK 4
|
||||
#endif
|
||||
|
||||
static TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK];
|
||||
static UINT __tx_iar_system_lock_next_free_mutex = 0;
|
||||
|
||||
|
||||
/* Define error counters, just for debug purposes. */
|
||||
|
||||
UINT __tx_iar_system_lock_no_mutexes;
|
||||
UINT __tx_iar_system_lock_internal_errors;
|
||||
UINT __tx_iar_system_lock_isr_caller;
|
||||
|
||||
|
||||
/* Define mutexes for IAR library. */
|
||||
|
||||
void __iar_system_Mtxinit(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT i;
|
||||
UINT status;
|
||||
TX_MUTEX *mutex_ptr;
|
||||
|
||||
|
||||
/* First, find a free mutex in the list. */
|
||||
for (i = 0; i < _MAX_LOCK; i++)
|
||||
{
|
||||
|
||||
/* Setup a pointer to the start of the next free mutex. */
|
||||
mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++];
|
||||
|
||||
/* Check for wrap-around on the next free mutex. */
|
||||
if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Yes, set the free index back to 0. */
|
||||
__tx_iar_system_lock_next_free_mutex = 0;
|
||||
}
|
||||
|
||||
/* Is this mutex free? */
|
||||
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Yes, this mutex is free, get out of the loop! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if a free mutex was found. */
|
||||
if (i >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Error! No more free mutexes! */
|
||||
|
||||
/* Increment the no mutexes error counter. */
|
||||
__tx_iar_system_lock_no_mutexes++;
|
||||
|
||||
/* Set return pointer to NULL. */
|
||||
*m = TX_NULL;
|
||||
|
||||
/* Return. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now create the ThreadX mutex for the IAR library. */
|
||||
status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT);
|
||||
|
||||
/* Determine if the creation was successful. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Yes, successful creation, return mutex pointer. */
|
||||
*m = (VOID *) mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the internal error counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
|
||||
/* Return a NULL pointer to indicate an error. */
|
||||
*m = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_system_Mtxdst(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
/* Simply delete the mutex. */
|
||||
_tx_mutex_delete((TX_MUTEX *) *m);
|
||||
}
|
||||
|
||||
void __iar_system_Mtxlock(__iar_Rmtx *m)
|
||||
{
|
||||
if (*m)
|
||||
{
|
||||
UINT status;
|
||||
|
||||
/* Determine the caller's context. Mutex locks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Get the mutex. */
|
||||
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_system_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_system_Mtxunlock(__iar_Rmtx *m)
|
||||
{
|
||||
if (*m)
|
||||
{
|
||||
UINT status;
|
||||
|
||||
/* Determine the caller's context. Mutex unlocks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Release the mutex. */
|
||||
status = _tx_mutex_put((TX_MUTEX *) *m);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_system_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_system_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if _DLIB_FILE_DESCRIPTOR
|
||||
|
||||
#include <stdio.h> /* Added to get access to FOPEN_MAX */
|
||||
#ifndef _MAX_FLOCK
|
||||
#define _MAX_FLOCK FOPEN_MAX /* Define _MAX_FLOCK as the maximum number of open files */
|
||||
#endif
|
||||
|
||||
|
||||
TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK];
|
||||
UINT __tx_iar_file_lock_next_free_mutex = 0;
|
||||
|
||||
|
||||
/* Define error counters, just for debug purposes. */
|
||||
|
||||
UINT __tx_iar_file_lock_no_mutexes;
|
||||
UINT __tx_iar_file_lock_internal_errors;
|
||||
UINT __tx_iar_file_lock_isr_caller;
|
||||
|
||||
|
||||
void __iar_file_Mtxinit(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT i;
|
||||
UINT status;
|
||||
TX_MUTEX *mutex_ptr;
|
||||
|
||||
|
||||
/* First, find a free mutex in the list. */
|
||||
for (i = 0; i < _MAX_FLOCK; i++)
|
||||
{
|
||||
|
||||
/* Setup a pointer to the start of the next free mutex. */
|
||||
mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++];
|
||||
|
||||
/* Check for wrap-around on the next free mutex. */
|
||||
if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Yes, set the free index back to 0. */
|
||||
__tx_iar_file_lock_next_free_mutex = 0;
|
||||
}
|
||||
|
||||
/* Is this mutex free? */
|
||||
if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Yes, this mutex is free, get out of the loop! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if a free mutex was found. */
|
||||
if (i >= _MAX_LOCK)
|
||||
{
|
||||
|
||||
/* Error! No more free mutexes! */
|
||||
|
||||
/* Increment the no mutexes error counter. */
|
||||
__tx_iar_file_lock_no_mutexes++;
|
||||
|
||||
/* Set return pointer to NULL. */
|
||||
*m = TX_NULL;
|
||||
|
||||
/* Return. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now create the ThreadX mutex for the IAR library. */
|
||||
status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT);
|
||||
|
||||
/* Determine if the creation was successful. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Yes, successful creation, return mutex pointer. */
|
||||
*m = (VOID *) mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the internal error counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
|
||||
/* Return a NULL pointer to indicate an error. */
|
||||
*m = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_file_Mtxdst(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
/* Simply delete the mutex. */
|
||||
_tx_mutex_delete((TX_MUTEX *) *m);
|
||||
}
|
||||
|
||||
void __iar_file_Mtxlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex locks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Get the mutex. */
|
||||
status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_file_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
|
||||
void __iar_file_Mtxunlock(__iar_Rmtx *m)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine the caller's context. Mutex unlocks are only available from initialization and
|
||||
threads. */
|
||||
if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS))
|
||||
{
|
||||
|
||||
/* Release the mutex. */
|
||||
status = _tx_mutex_put((TX_MUTEX *) *m);
|
||||
|
||||
/* Check the status of the mutex release. */
|
||||
if (status)
|
||||
{
|
||||
|
||||
/* Internal error, increment the counter. */
|
||||
__tx_iar_file_lock_internal_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the ISR caller error. */
|
||||
__tx_iar_file_lock_isr_caller++;
|
||||
}
|
||||
}
|
||||
#endif /* _DLIB_FILE_DESCRIPTOR */
|
||||
|
||||
#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */
|
||||
|
||||
#endif /* IAR version 8 and above. */
|
||||
@@ -0,0 +1,239 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
|
||||
IRQ_MODE EQU 0x12 ; IRQ mode
|
||||
SVC_MODE EQU 0x13 ; SVC mode
|
||||
SYS_MODE EQU 0x1F ; SYS mode
|
||||
DISABLE_INTS DEFINE 0x80 ; Disable IRQ interrupts
|
||||
THUMB_MASK DEFINE 0x20 ; Thumb bit mask
|
||||
|
||||
;
|
||||
EXTERN _tx_thread_system_state
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _tx_thread_execute_ptr
|
||||
EXTERN _tx_timer_time_slice
|
||||
EXTERN _tx_thread_schedule
|
||||
EXTERN _tx_thread_preempt_disable
|
||||
EXTERN _tx_execution_isr_exit
|
||||
;
|
||||
;
|
||||
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_context_restore Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function restores the interrupt context if it is processing a */
|
||||
;/* nested interrupt. If not, it returns to the interrupt thread if no */
|
||||
;/* preemption is necessary. Otherwise, if preemption is necessary or */
|
||||
;/* if no thread was running, the function returns to the scheduler. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* _tx_thread_schedule Thread scheduling routine */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ISRs Interrupt Service Routines */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_context_restore(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_context_restore
|
||||
ARM
|
||||
_tx_thread_context_restore
|
||||
;
|
||||
; /* Lockout interrupts. */
|
||||
;
|
||||
CPSID i ; Disable IRQ interrupts
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR exit function to indicate an ISR is complete. */
|
||||
;
|
||||
BL _tx_execution_isr_exit ; Call the ISR exit function
|
||||
#endif
|
||||
;
|
||||
; /* Determine if interrupts are nested. */
|
||||
; if (--_tx_thread_system_state)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_system_state ; Pickup address of system state var
|
||||
LDR r2, [r3] ; Pickup system state
|
||||
SUB r2, r2, #1 ; Decrement the counter
|
||||
STR r2, [r3] ; Store the counter
|
||||
CMP r2, #0 ; Was this the first interrupt?
|
||||
BEQ __tx_thread_not_nested_restore ; If so, not a nested restore
|
||||
;
|
||||
; /* Interrupts are nested. */
|
||||
;
|
||||
; /* Just recover the saved registers and return to the point of
|
||||
; interrupt. */
|
||||
;
|
||||
LDMIA sp!, {r0, r10, r12, lr} ; Recover SPSR, POI, and scratch regs
|
||||
MSR SPSR_cxsf, r0 ; Put SPSR back
|
||||
LDMIA sp!, {r0-r3} ; Recover r0-r3
|
||||
MOVS pc, lr ; Return to point of interrupt
|
||||
;
|
||||
; }
|
||||
__tx_thread_not_nested_restore
|
||||
;
|
||||
; /* Determine if a thread was interrupted and no preemption is required. */
|
||||
; else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr)
|
||||
; || (_tx_thread_preempt_disable))
|
||||
; {
|
||||
;
|
||||
LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr
|
||||
LDR r0, [r1] ; Pickup actual current thread pointer
|
||||
CMP r0, #0 ; Is it NULL?
|
||||
BEQ __tx_thread_idle_system_restore ; Yes, idle system was interrupted
|
||||
;
|
||||
LDR r3, =_tx_thread_preempt_disable ; Pickup preempt disable address
|
||||
LDR r2, [r3] ; Pickup actual preempt disable flag
|
||||
CMP r2, #0 ; Is it set?
|
||||
BNE __tx_thread_no_preempt_restore ; Yes, don't preempt this thread
|
||||
LDR r3, =_tx_thread_execute_ptr ; Pickup address of execute thread ptr
|
||||
LDR r2, [r3] ; Pickup actual execute thread pointer
|
||||
CMP r0, r2 ; Is the same thread highest priority?
|
||||
BNE __tx_thread_preempt_restore ; No, preemption needs to happen
|
||||
;
|
||||
;
|
||||
__tx_thread_no_preempt_restore
|
||||
;
|
||||
; /* Restore interrupted thread or ISR. */
|
||||
;
|
||||
; /* Pickup the saved stack pointer. */
|
||||
; tmp_ptr = _tx_thread_current_ptr -> tx_thread_stack_ptr;
|
||||
;
|
||||
; /* Recover the saved context and return to the point of interrupt. */
|
||||
;
|
||||
LDMIA sp!, {r0, r10, r12, lr} ; Recover SPSR, POI, and scratch regs
|
||||
MSR SPSR_cxsf, r0 ; Put SPSR back
|
||||
LDMIA sp!, {r0-r3} ; Recover r0-r3
|
||||
MOVS pc, lr ; Return to point of interrupt
|
||||
;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
__tx_thread_preempt_restore
|
||||
;
|
||||
LDMIA sp!, {r3, r10, r12, lr} ; Recover temporarily saved registers
|
||||
MOV r1, lr ; Save lr (point of interrupt)
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
STR r1, [sp, #-4]! ; Save point of interrupt on thread's stack
|
||||
STMDB sp!, {r4-r12, lr} ; Save upper half of registers on thread's stack
|
||||
MOV r4, r3 ; Save SPSR in r4
|
||||
CPS #IRQ_MODE ; Enter IRQ mode
|
||||
LDMIA sp!, {r0-r3} ; Recover r0-r3
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
STMDB sp!, {r0-r3} ; Save r0-r3 on thread's stack
|
||||
|
||||
LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr
|
||||
LDR r0, [r1, #0] ; Pickup current thread pointer
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
LDR r2, [r0, #144] ; Pickup the VFP enabled flag
|
||||
CMP r2, #0 ; Is the VFP enabled?
|
||||
BEQ _tx_skip_irq_vfp_save ; No, skip VFP IRQ save
|
||||
VMRS r2, FPSCR ; Pickup the FPSCR
|
||||
STR r2, [sp, #-4]! ; Save FPSCR
|
||||
VSTMDB sp!, {D0-D15} ; Save D0-D15
|
||||
_tx_skip_irq_vfp_save
|
||||
#endif
|
||||
|
||||
MOV r3, #1 ; Build interrupt stack type
|
||||
STMDB sp!, {r3, r4} ; Save interrupt stack type and SPSR
|
||||
STR sp, [r0, #8] ; Save stack pointer in thread control
|
||||
; block
|
||||
;
|
||||
; /* Save the remaining time-slice and disable it. */
|
||||
; if (_tx_timer_time_slice)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_timer_time_slice ; Pickup time-slice variable address
|
||||
LDR r2, [r3] ; Pickup time-slice
|
||||
CMP r2, #0 ; Is it active?
|
||||
BEQ __tx_thread_dont_save_ts ; No, don't save it
|
||||
;
|
||||
; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
|
||||
; _tx_timer_time_slice = 0;
|
||||
;
|
||||
STR r2, [r0, #24] ; Save thread's time-slice
|
||||
MOV r2, #0 ; Clear value
|
||||
STR r2, [r3] ; Disable global time-slice flag
|
||||
;
|
||||
; }
|
||||
__tx_thread_dont_save_ts
|
||||
;
|
||||
;
|
||||
; /* Clear the current task pointer. */
|
||||
; _tx_thread_current_ptr = TX_NULL;
|
||||
;
|
||||
MOV r0, #0 ; NULL value
|
||||
STR r0, [r1] ; Clear current thread pointer
|
||||
;
|
||||
; /* Return to the scheduler. */
|
||||
; _tx_thread_schedule();
|
||||
;
|
||||
CPS #IRQ_MODE ; Enter IRQ mode
|
||||
MRS r1, SPSR ; Get SPSR
|
||||
ORR r1, r1, #SYS_MODE ; Change to SYS Mode
|
||||
BIC r1, r1, #THUMB_MASK ; Clear thumb bit - slarson
|
||||
MSR SPSR_cxsf, r1 ; Put SYS Mode in SPSR
|
||||
LDR lr, =_tx_thread_schedule ; Load scheduler address
|
||||
MOVS pc, lr ; Return to scheduler
|
||||
; }
|
||||
;
|
||||
__tx_thread_idle_system_restore
|
||||
;
|
||||
; /* Just return back to the scheduler! */
|
||||
;
|
||||
LDR lr, =_tx_thread_schedule ; Load scheduler address
|
||||
MOVS pc, lr ; Return to scheduler
|
||||
;}
|
||||
;
|
||||
END
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
EXTERN _tx_thread_system_state
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN __tx_irq_processing_return
|
||||
EXTERN _tx_execution_isr_enter
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_context_save Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function saves the context of an executing thread in the */
|
||||
;/* beginning of interrupt processing. The function also ensures that */
|
||||
;/* the system stack is used upon return to the calling ISR. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ISRs */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_context_save(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_context_save
|
||||
ARM
|
||||
_tx_thread_context_save
|
||||
;
|
||||
; /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
|
||||
; out, we are in IRQ mode, and all registers are intact. */
|
||||
;
|
||||
; /* Check for a nested interrupt condition. */
|
||||
; if (_tx_thread_system_state++)
|
||||
; {
|
||||
;
|
||||
STMDB sp!, {r0-r3} ; Save some working registers
|
||||
LDR r3, =_tx_thread_system_state ; Pickup address of system state var
|
||||
LDR r2, [r3, #0] ; Pickup system state
|
||||
CMP r2, #0 ; Is this the first interrupt?
|
||||
BEQ __tx_thread_not_nested_save ; Yes, not a nested context save
|
||||
;
|
||||
; /* Nested interrupt condition. */
|
||||
;
|
||||
ADD r2, r2, #1 ; Increment the interrupt counter
|
||||
STR r2, [r3, #0] ; Store it back in the variable
|
||||
;
|
||||
; /* Save the rest of the scratch registers on the stack and return to the
|
||||
; calling ISR. */
|
||||
;
|
||||
MRS r0, SPSR ; Pickup saved SPSR
|
||||
SUB lr, lr, #4 ; Adjust point of interrupt
|
||||
STMDB sp!, {r0, r10, r12, lr} ; Store other registers
|
||||
;
|
||||
; /* Return to the ISR. */
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_irq_processing_return ; Continue IRQ processing
|
||||
;
|
||||
__tx_thread_not_nested_save
|
||||
; }
|
||||
;
|
||||
; /* Otherwise, not nested, check to see if a thread was running. */
|
||||
; else if (_tx_thread_current_ptr)
|
||||
; {
|
||||
;
|
||||
ADD r2, r2, #1 ; Increment the interrupt counter
|
||||
STR r2, [r3, #0] ; Store it back in the variable
|
||||
LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr
|
||||
LDR r0, [r1, #0] ; Pickup current thread pointer
|
||||
CMP r0, #0 ; Is it NULL?
|
||||
BEQ __tx_thread_idle_system_save ; If so, interrupt occured in
|
||||
; scheduling loop - nothing needs saving!
|
||||
;
|
||||
; /* Save minimal context of interrupted thread. */
|
||||
;
|
||||
MRS r2, SPSR ; Pickup saved SPSR
|
||||
SUB lr, lr, #4 ; Adjust point of interrupt
|
||||
STMDB sp!, {r2, r10, r12, lr} ; Store other registers
|
||||
;
|
||||
; /* Save the current stack pointer in the thread's control block. */
|
||||
; _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
;
|
||||
; /* Switch to the system stack. */
|
||||
; sp = _tx_thread_system_stack_ptr;
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
B __tx_irq_processing_return ; Continue IRQ processing
|
||||
;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
;
|
||||
__tx_thread_idle_system_save
|
||||
;
|
||||
; /* Interrupt occurred in the scheduling loop. */
|
||||
;
|
||||
; /* Not much to do here, just adjust the stack pointer, and return to IRQ
|
||||
; processing. */
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
ADD sp, sp, #16 ; Recover saved registers
|
||||
B __tx_irq_processing_return ; Continue IRQ processing
|
||||
;
|
||||
; }
|
||||
;}
|
||||
;
|
||||
|
||||
;
|
||||
;
|
||||
END
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
|
||||
INT_MASK DEFINE 0x80 ; Interrupt bit mask
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_interrupt_control Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is responsible for changing the interrupt lockout */
|
||||
;/* posture of the system. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* new_posture New interrupt lockout posture */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* old_posture Old interrupt lockout posture */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* Application Code */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;UINT _tx_thread_interrupt_control(UINT new_posture)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_interrupt_control
|
||||
ARM
|
||||
_tx_thread_interrupt_control
|
||||
;
|
||||
; /* Pickup current interrupt lockout posture. */
|
||||
;
|
||||
MRS r3, CPSR ; Pickup current CPSR
|
||||
BIC r1, r3, #INT_MASK ; Clear interrupt lockout bits
|
||||
ORR r1, r1, r0 ; Or-in new interrupt lockout bits
|
||||
;
|
||||
; /* Apply the new interrupt posture. */
|
||||
;
|
||||
MSR CPSR_cxsf, r1 ; Setup new CPSR
|
||||
AND r0, r3, #INT_MASK ; Return previous interrupt mask
|
||||
|
||||
BX lr ; Return to caller
|
||||
;
|
||||
;}
|
||||
;
|
||||
;
|
||||
END
|
||||
@@ -0,0 +1,81 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
DISABLE_INTS DEFINE 0x80 ; IRQ interrupts disabled
|
||||
;
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_interrupt_disable Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is responsible for disabling interrupts */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* old_posture Old interrupt lockout posture */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* Application Code */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;UINT _tx_thread_interrupt_disable(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_interrupt_disable
|
||||
ARM
|
||||
_tx_thread_interrupt_disable??rA
|
||||
_tx_thread_interrupt_disable
|
||||
;
|
||||
; /* Pickup current interrupt lockout posture. */
|
||||
;
|
||||
MRS r0, CPSR ; Pickup current CPSR
|
||||
CPSID i ; Mask interrupts
|
||||
BX lr ; Return to caller
|
||||
;}
|
||||
;
|
||||
;
|
||||
END
|
||||
@@ -0,0 +1,76 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_interrupt_restore Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is responsible for restoring interrupts to the state */
|
||||
;/* returned by a previous _tx_thread_interrupt_disable call. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* old_posture Old interrupt lockout posture */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* Application Code */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;void _tx_thread_interrupt_restore(UINT old_posture)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_interrupt_restore
|
||||
ARM
|
||||
_tx_thread_interrupt_restore
|
||||
;
|
||||
; /* Apply the new interrupt posture. */
|
||||
;
|
||||
MSR CPSR_cxsf, r0 ; Setup new CPSR
|
||||
|
||||
BX lr ; Return to caller
|
||||
;}
|
||||
;
|
||||
END
|
||||
@@ -0,0 +1,89 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
IRQ_MODE DEFINE 0x12 ; IRQ mode
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_irq_nesting_end Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is called by the application from IRQ mode after */
|
||||
;/* _tx_thread_irq_nesting_start has been called and switches the IRQ */
|
||||
;/* processing from system mode back to IRQ mode prior to the ISR */
|
||||
;/* calling _tx_thread_context_restore. Note that this function */
|
||||
;/* assumes the system stack pointer is in the same position after */
|
||||
;/* nesting start function was called. */
|
||||
;/* */
|
||||
;/* This function assumes that the system mode stack pointer was setup */
|
||||
;/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
;/* */
|
||||
;/* This function returns with IRQ interrupts disabled. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ISRs */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_irq_nesting_end(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_irq_nesting_end
|
||||
ARM
|
||||
_tx_thread_irq_nesting_end
|
||||
MOV r3, lr ; Save ISR return address
|
||||
CPSID i ; Disable interrupts
|
||||
POP {lr} ; Pickup saved lr
|
||||
CPS #IRQ_MODE ; Switch to IRQ mode
|
||||
MOV pc, r3 ; Return to ISR
|
||||
;}
|
||||
;
|
||||
;
|
||||
END
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
SYS_MODE DEFINE 0x1F ; System mode
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_irq_nesting_start Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is called by the application from IRQ mode after */
|
||||
;/* _tx_thread_context_save has been called and switches the IRQ */
|
||||
;/* processing to the system mode so nested IRQ interrupt processing */
|
||||
;/* is possible (system mode has its own "lr" register). Note that */
|
||||
;/* this function assumes that the system mode stack pointer was setup */
|
||||
;/* during low-level initialization (tx_initialize_low_level.s). */
|
||||
;/* */
|
||||
;/* This function returns with IRQ interrupts enabled. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ISRs */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_irq_nesting_start(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_irq_nesting_start
|
||||
ARM
|
||||
_tx_thread_irq_nesting_start
|
||||
MOV r3, lr ; Save ISR return address
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
PUSH {lr} ; Save system mode lr on the system mode stack
|
||||
CPSIE i ; Enable interrupts
|
||||
MOV pc, r3 ; Return to ISR
|
||||
;}
|
||||
;
|
||||
;
|
||||
END
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
EXTERN _tx_thread_execute_ptr
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _tx_timer_time_slice
|
||||
EXTERN _tx_execution_thread_enter
|
||||
;
|
||||
IMPORT _txm_system_mode_enter
|
||||
IMPORT _txm_system_mode_exit
|
||||
;
|
||||
THUMB_MASK EQU 0x20 ; Thumb bit (5) of CPSR/SPSR.
|
||||
IRQ_MODE EQU 0x12 ; IRQ mode
|
||||
USR_MODE EQU 0x10 ; USR mode
|
||||
SVC_MODE EQU 0x13 ; SVC mode
|
||||
SYS_MODE EQU 0x1F ; SYS mode
|
||||
MODE_MASK EQU 0x1F ; Mode mask
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_schedule Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function waits for a thread control block pointer to appear in */
|
||||
;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */
|
||||
;/* in the variable, the corresponding thread is resumed. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* _tx_initialize_kernel_enter ThreadX entry function */
|
||||
;/* _tx_thread_system_return Return to system from thread */
|
||||
;/* _tx_thread_context_restore Restore thread's context */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_schedule(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_schedule
|
||||
ARM
|
||||
_tx_thread_schedule??rA
|
||||
_tx_thread_schedule
|
||||
|
||||
; Enter the scheduler.
|
||||
SVC 0
|
||||
|
||||
; We should never get here - ever!
|
||||
_tx_scheduler_fault__
|
||||
B _tx_scheduler_fault__
|
||||
;}
|
||||
; ****************************************************************************
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; SWI_Handler
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC SWI_Handler
|
||||
ARM
|
||||
SWI_Handler
|
||||
|
||||
STMFD sp!, {r0-r3, r12, lr} ; Store the registers
|
||||
MOV r1, sp ; Set pointer to parameters
|
||||
MRS r0, spsr ; Get spsr
|
||||
STMFD sp!, {r0, r3} ; Store spsr onto stack and another
|
||||
; register to maintain 8-byte-aligned stack
|
||||
TST r0, #THUMB_MASK ; Occurred in Thumb state?
|
||||
LDRNEH r0, [lr,#-2] ; Yes: Load halfword and...
|
||||
BICNE r0, r0, #0xFF00 ; ...extract comment field
|
||||
LDREQ r0, [lr,#-4] ; No: Load word and...
|
||||
BICEQ r0, r0, #0xFF000000 ; ...extract comment field
|
||||
|
||||
; r0 now contains SVC number
|
||||
; r1 now contains pointer to stacked registers
|
||||
|
||||
;
|
||||
; The service call is handled here
|
||||
;
|
||||
|
||||
CMP r0, #0 ; Is it a schedule request?
|
||||
BEQ _tx_handler_svc_schedule ; Yes, go there
|
||||
|
||||
CMP r0, #1 ; Is it a system mode enter request?
|
||||
BEQ _tx_handler_svc_super_enter ; Yes, go there
|
||||
|
||||
CMP r0, #2 ; Is it a system mode exit request?
|
||||
BEQ _tx_handler_svc_super_exit ; Yes, go there
|
||||
|
||||
LDR r2, =0x123456
|
||||
CMP r0, r2 ; Is it an ARM request?
|
||||
BEQ _tx_handler_svc_arm ; Yes, go there
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Unknown SVC argument
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Unrecognized service call
|
||||
_tx_handler_svc_unrecognized
|
||||
|
||||
_tx_handler_svc_unrecognized_loop ; We should never get here
|
||||
B _tx_handler_svc_unrecognized_loop
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; SVC 1
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; At this point we have an SVC 1, which means we are entering
|
||||
; supervisor mode to service a kernel call.
|
||||
_tx_handler_svc_super_enter
|
||||
; Make sure that we have been called from the system mode enter location (security)
|
||||
LDR r2, =_txm_system_mode_enter ; Load the address of the known call point
|
||||
SUB r1, lr, #4 ; Calculate the address of the actual call
|
||||
CMP r1, r2 ; Did we come from txm_module_manager_user_mode_entry?
|
||||
BNE _tx_handler_svc_unrecognized ; Return to where we came
|
||||
|
||||
; Clear the user mode flag in the thread structure
|
||||
LDR r1, =_tx_thread_current_ptr ; Load the current thread pointer address
|
||||
LDR r2, [r1] ; Load current thread location from the pointer (pointer indirection)
|
||||
MOV r1, #0 ; Load the new user mode flag value (user mode flag clear -> not user mode -> system)
|
||||
STR r1, [r2, #0x9C] ; Clear the current user mode selection for thread
|
||||
|
||||
; Now we enter the system mode and return
|
||||
LDMFD sp!, {r0, r3} ; Get spsr from the stack
|
||||
BIC r0, r0, #MODE_MASK ; clear mode field
|
||||
ORR r0, r0, #SYS_MODE ; system mode code
|
||||
MSR SPSR_cxsf, r0 ; Restore the spsr
|
||||
|
||||
LDR r1, [r2, #0xA8] ; Load the module kernel stack pointer
|
||||
CPS #SYS_MODE ; Switch to SYS mode
|
||||
MOV r3, sp ; Grab thread stack pointer
|
||||
MOV sp, r1 ; Set SP to kernel stack pointer
|
||||
CPS #SVC_MODE ; Switch back to SVC mode
|
||||
STR r3, [r2, #0xB0] ; Save thread stack pointer
|
||||
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
|
||||
LDR r3, [r2, #0xAC] ; Load the module kernel stack size
|
||||
STR r3, [r2, #20] ; Set stack size
|
||||
LDRD r0, r1, [r2, #0xA4] ; Load the module kernel stack start and end
|
||||
STRD r0, r1, [r2, #0x0C] ; Set stack start and end
|
||||
#endif
|
||||
LDMFD sp!, {r0-r3, r12, pc}^ ; Restore the registers and return
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; SVC 2
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; At this point we have an SVC 2, which means we are exiting
|
||||
; supervisor mode after servicing a kernel call.
|
||||
_tx_handler_svc_super_exit
|
||||
; Make sure that we have been called from the system mode exit location (security)
|
||||
LDR r2, =_txm_system_mode_exit ; Load the address of the known call point
|
||||
SUB r1, lr, #4 ; Calculate the address of the actual call
|
||||
CMP r1, r2 ; Did we come from txm_module_manager_user_mode_entry?
|
||||
BNE _tx_handler_svc_unrecognized ; Return to where we came
|
||||
|
||||
; Set the user mode flag into the thread structure
|
||||
LDR r1, =_tx_thread_current_ptr ; Load the current thread pointer address
|
||||
LDR r2, [r1] ; Load the current thread location from the pointer (pointer indirection)
|
||||
MOV r1, #1 ; Load the new user mode flag value (user mode enabled -> not system anymore)
|
||||
STR r1, [r2, #0x9C] ; Clear the current user mode selection for thread
|
||||
|
||||
; Now we enter user mode (exit the system mode) and return
|
||||
LDMFD sp!, {r0, r3} ; Get spsr from the stack
|
||||
BIC r0, r0, #MODE_MASK ; clear mode field
|
||||
ORR r0, r0, #USR_MODE ; user mode code
|
||||
MSR SPSR_cxsf, r0 ; Restore the spsr
|
||||
|
||||
LDR r1, [r2, #0xB0] ; Load the module thread stack pointer
|
||||
CPS #SYS_MODE ; Switch to SYS mode
|
||||
MOV sp, r1 ; Set SP back to thread stack pointer
|
||||
CPS #SVC_MODE ; Switch back to SVC mode
|
||||
#ifndef TXM_MODULE_KERNEL_STACK_MAINTENANCE_DISABLE
|
||||
LDR r3, [r2, #0xBC] ; Load the module thread stack size
|
||||
STR r3, [r2, #20] ; Set stack size
|
||||
LDRD r0, r1, [r2, #0xB4] ; Load the module thread stack start and end
|
||||
STRD r0, r1, [r2, #0x0C] ; Set stack start and end
|
||||
#endif
|
||||
LDMFD sp!, {r0-r3, r12, pc}^ ; Restore the registers and return
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; ARM Semihosting
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
_tx_handler_svc_arm
|
||||
|
||||
; *** TODO: handle semihosting requests or ARM angel requests ***
|
||||
|
||||
; just return
|
||||
LDMFD sp!, {r0, r3} ; Get spsr from the stack
|
||||
MSR SPSR_cxsf, r0 ; Restore the spsr
|
||||
LDMFD sp!, {r0-r3, r12, pc}^ ; Restore the registers and return
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; SVC 0
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; At this point we have an SVC 0: enter the scheduler.
|
||||
_tx_handler_svc_schedule
|
||||
|
||||
LDMFD sp!, {r0, r3} ; Get spsr from stack
|
||||
MSR SPSR_cxsf, r0 ; Restore spsr
|
||||
LDMFD sp!, {r0-r3, r12, lr} ; Restore the registers
|
||||
|
||||
; This code waits for a thread control block pointer to appear in
|
||||
; the _tx_thread_execute_ptr variable. Once a thread pointer appears
|
||||
; in the variable, the corresponding thread is resumed.
|
||||
;
|
||||
; /* Enable interrupts. */
|
||||
;
|
||||
CPSIE i ; Enable IRQ interrupts
|
||||
|
||||
;
|
||||
; /* Wait for a thread to execute. */
|
||||
; do
|
||||
; {
|
||||
LDR r1, =_tx_thread_execute_ptr ; Address of thread execute ptr
|
||||
;
|
||||
__tx_thread_schedule_loop
|
||||
LDR r0, [r1, #0] ; Pickup next thread to execute
|
||||
CMP r0, #0 ; Is it NULL?
|
||||
BEQ __tx_thread_schedule_loop ; If so, keep looking for a thread
|
||||
;
|
||||
; }
|
||||
; while(_tx_thread_execute_ptr == TX_NULL);
|
||||
;
|
||||
; /* Yes! We have a thread to execute. Lockout interrupts and
|
||||
; transfer control to it. */
|
||||
;
|
||||
CPSID i ; Disable interrupts
|
||||
;
|
||||
; /* Setup the current thread pointer. */
|
||||
; _tx_thread_current_ptr = _tx_thread_execute_ptr;
|
||||
;
|
||||
LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread
|
||||
STR r0, [r1, #0] ; Setup current thread pointer
|
||||
;
|
||||
; /* Increment the run count for this thread. */
|
||||
; _tx_thread_current_ptr -> tx_thread_run_count++;
|
||||
;
|
||||
LDR r2, [r0, #4] ; Pickup run counter
|
||||
LDR r3, [r0, #24] ; Pickup time-slice for this thread
|
||||
ADD r2, r2, #1 ; Increment thread run-counter
|
||||
STR r2, [r0, #4] ; Store the new run counter
|
||||
;
|
||||
; /* Setup time-slice, if present. */
|
||||
; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice;
|
||||
;
|
||||
LDR r2, =_tx_timer_time_slice ; Pickup address of time slice variable
|
||||
STR r3, [r2, #0] ; Setup time-slice
|
||||
;
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the thread entry function to indicate the thread is executing. */
|
||||
;
|
||||
MOV r5, r0 ; Save r0
|
||||
BL _tx_execution_thread_enter ; Call the thread execution enter function
|
||||
MOV r0, r5 ; Restore r0
|
||||
#endif
|
||||
|
||||
; Determine if an interrupt frame or a synchronous task suspension frame is present.
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
LDR sp, [r0, #8] ; Switch to thread stack pointer
|
||||
LDMIA sp!, {r4, r5} ; Pickup the stack type and saved CPSR
|
||||
CPS #SVC_MODE ; Enter SVC mode
|
||||
|
||||
; **************************************************************************
|
||||
; Set up MPU for module.
|
||||
LDR r1, [r0, #0x94] ; Pickup module instance pointer
|
||||
CMP r1, #0 ; Valid module pointer?
|
||||
BEQ _tx_end_mpu_update ; No - skip memory protection setup
|
||||
LDR r2, [r0, #0xA0] ; Pickup tx_thread_module_user_mode
|
||||
CMP r2, #1 ; In user mode?
|
||||
BNE _tx_end_mpu_update ; No - skip memory protection setup
|
||||
; Is the MPU already set up for this module?
|
||||
; Pickup the first data entry to check (txm_module_instance_mpu_registers[5])
|
||||
LDR r2, [r1, #0xA0] ; Pickup txm_module_instance_mpu_registers[5]
|
||||
MOV r3, #5 ; Select region 5
|
||||
MCR p15, 0, r3, c6, c2, 0 ; Select region 5
|
||||
MRC p15, 0, r3, c6, c1, 0 ; Read DRBAR into r3
|
||||
CMP r2, r3 ; Is module already loaded?
|
||||
BEQ _tx_end_mpu_update ; Yes - skip memory protection setup
|
||||
|
||||
; Disable MPU before applying new regions.
|
||||
MRC p15, 0, r2, c1, c0, 0 ; Read SCTLR
|
||||
BIC r2, r2, #1 ; Disable MPU
|
||||
DSB
|
||||
MCR p15, 0, r2, c1, c0, 0 ; Write to SCTLR
|
||||
ISB
|
||||
; Loop to load MPU registers
|
||||
MOV r3, #0 ; Loop index
|
||||
ADD r1, r1, #0x64 ; Build address of MPU register table
|
||||
_tx_mpu_loop
|
||||
LDR r2, [r1] ; Pickup txm_module_mpu_region_address
|
||||
MCR p15, 0, r3, c6, c2, 0 ; Select region
|
||||
MCR p15, 0, r2, c6, c1, 0 ; Write to DRBAR
|
||||
ADD r1, r1, #4 ; Increment to next MPU parameter
|
||||
LDR r2, [r1] ; Pickup txm_module_mpu_region_size
|
||||
MCR p15, 0, r2, c6, c1, 2 ; Write to DRSR
|
||||
ADD r1, r1, #4 ; Increment to next MPU parameter
|
||||
LDR r2, [r1] ; Pickup txm_module_mpu_region_attributes
|
||||
MCR p15, 0, r2, c6, c1, 4 ; Write to DRACR
|
||||
ADD r1, r1, #4 ; Increment to next MPU parameter
|
||||
ADD r3, r3, #1 ; Increment loop index
|
||||
CMP r3, #0xB ; Check the limit
|
||||
BLE _tx_mpu_loop ; Loop if not finished
|
||||
|
||||
; Enable MPU with new regions.
|
||||
MRC p15, 0, r2, c1, c0, 0 ; Read SCTLR
|
||||
ORR r2, r2, #1 ; Enable MPU
|
||||
ORR r2, r2, #0x20000 ; Enable Background Region
|
||||
DSB
|
||||
MCR p15, 0, r2, c1, c0, 0 ; Write to SCTLR
|
||||
ISB
|
||||
;
|
||||
_tx_end_mpu_update
|
||||
; **************************************************************************
|
||||
|
||||
CMP r4, #0 ; Check for synchronous context switch
|
||||
BEQ _tx_solicited_return
|
||||
|
||||
MSR SPSR_cxsf, r5 ; Setup SPSR for return
|
||||
LDR r1, [r0, #8] ; Get thread SP
|
||||
LDR lr, [r1, #0x40] ; Get thread PC
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
LDR r2, [r0, #144] ; Pickup the VFP enabled flag
|
||||
CMP r2, #0 ; Is the VFP enabled?
|
||||
BEQ _tx_skip_interrupt_vfp_restore ; No, skip VFP interrupt restore
|
||||
VLDMIA sp!, {D0-D15} ; Recover D0-D15
|
||||
LDR r4, [sp], #4 ; Pickup FPSCR
|
||||
VMSR FPSCR, r4 ; Restore FPSCR
|
||||
CPS #SVC_MODE ; Enter SVC mode
|
||||
LDR lr, [r1, #0x144] ; Get thread PC
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
_tx_skip_interrupt_vfp_restore
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r0-r12, lr} ; Restore registers
|
||||
ADD sp, sp, #4 ; Fix stack pointer
|
||||
CPS #SVC_MODE ; Enter SVC mode
|
||||
SUBS pc, lr, #0 ; Return to point of thread interrupt
|
||||
|
||||
_tx_solicited_return
|
||||
MOV r2, r5 ; Move CPSR to scratch register
|
||||
CPS #SYS_MODE ; Enter SYS mode
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
LDR r1, [r0, #144] ; Pickup the VFP enabled flag
|
||||
CMP r1, #0 ; Is the VFP enabled?
|
||||
BEQ _tx_skip_solicited_vfp_restore ; No, skip VFP solicited restore
|
||||
VLDMIA sp!, {D8-D15} ; Recover D8-D15
|
||||
LDR r4, [sp], #4 ; Pickup FPSCR
|
||||
VMSR FPSCR, r4 ; Restore FPSCR
|
||||
_tx_skip_solicited_vfp_restore
|
||||
#endif
|
||||
|
||||
LDMIA sp!, {r4-r11, lr} ; Restore registers
|
||||
MOV r1, lr ; Copy lr to r1 to preserve across mode change
|
||||
CPS #SVC_MODE ; Enter SVC mode
|
||||
MSR SPSR_cxsf, r2 ; Recover CPSR
|
||||
SUBS pc, r1, #0 ; Return to thread synchronously
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; End SWI_Handler
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
PUBLIC tx_thread_vfp_enable
|
||||
CODE32
|
||||
tx_thread_vfp_enable??rA
|
||||
tx_thread_vfp_enable
|
||||
MRS r2, CPSR ; Pickup the CPSR
|
||||
CPSID i ; Disable IRQ interrupts
|
||||
LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address
|
||||
LDR r1, [r0] ; Pickup current thread pointer
|
||||
CMP r1, #0 ; Check for NULL thread pointer
|
||||
BEQ __tx_no_thread_to_enable ; If NULL, skip VFP enable
|
||||
MOV r0, #1 ; Build enable value
|
||||
STR r0, [r1, #144] ; Set the VFP enable flag (tx_thread_vfp_enable field in TX_THREAD)
|
||||
__tx_no_thread_to_enable:
|
||||
MSR CPSR_cxsf, r2 ; Recover CPSR
|
||||
BX LR ; Return to caller
|
||||
|
||||
PUBLIC tx_thread_vfp_disable
|
||||
CODE32
|
||||
tx_thread_vfp_disable??rA
|
||||
tx_thread_vfp_disable
|
||||
MRS r2, CPSR ; Pickup the CPSR
|
||||
CPSID i ; Disable IRQ interrupts
|
||||
LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address
|
||||
LDR r1, [r0] ; Pickup current thread pointer
|
||||
CMP r1, #0 ; Check for NULL thread pointer
|
||||
BEQ __tx_no_thread_to_disable ; If NULL, skip VFP disable
|
||||
MOV r0, #0 ; Build disable value
|
||||
STR r0, [r1, #144] ; Clear the VFP enable flag (tx_thread_vfp_enable field in TX_THREAD)
|
||||
__tx_no_thread_to_disable:
|
||||
MSR CPSR_cxsf, r2 ; Recover CPSR
|
||||
BX LR ; Return to caller
|
||||
#endif
|
||||
|
||||
END
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
SYS_MODE DEFINE 0x1F ; SYS mode
|
||||
CPSR_MASK DEFINE 0x9F ; Mask initial CPSR, IRQ ints enabled
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_stack_build Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function builds a stack frame on the supplied thread's stack. */
|
||||
;/* The stack frame results in a fake interrupt return to the supplied */
|
||||
;/* function pointer. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* thread_ptr Pointer to thread control blk */
|
||||
;/* function_ptr Pointer to return function */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* _tx_thread_create Create thread service */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_stack_build
|
||||
|
||||
ARM
|
||||
_tx_thread_stack_build
|
||||
;
|
||||
;
|
||||
; /* Build a fake interrupt frame. The form of the fake interrupt stack
|
||||
; on the Cortex-R4 should look like the following after it is built:
|
||||
;
|
||||
; Stack Top: 1 Interrupt stack frame type
|
||||
; CPSR Initial value for CPSR
|
||||
; a1 (r0) Initial value for a1
|
||||
; a2 (r1) Initial value for a2
|
||||
; a3 (r2) Initial value for a3
|
||||
; a4 (r3) Initial value for a4
|
||||
; v1 (r4) Initial value for v1
|
||||
; v2 (r5) Initial value for v2
|
||||
; v3 (r6) Initial value for v3
|
||||
; v4 (r7) Initial value for v4
|
||||
; v5 (r8) Initial value for v5
|
||||
; sb (r9) Initial value for sb
|
||||
; sl (r10) Initial value for sl
|
||||
; fp (r11) Initial value for fp
|
||||
; ip (r12) Initial value for ip
|
||||
; lr (r14) Initial value for lr
|
||||
; pc (r15) Initial value for pc
|
||||
; 0 For stack backtracing
|
||||
;
|
||||
; Stack Bottom: (higher memory address) */
|
||||
;
|
||||
LDR r2, [r0, #16] ; Pickup end of stack area
|
||||
BIC r2, r2, #7 ; Ensure 8-byte alignment
|
||||
SUB r2, r2, #76 ; Allocate space for the stack frame
|
||||
;
|
||||
; /* Actually build the stack frame. */
|
||||
;
|
||||
MOV r3, #1 ; Build interrupt stack type
|
||||
STR r3, [r2, #0] ; Store stack type
|
||||
MOV r3, #0 ; Build initial register value
|
||||
STR r3, [r2, #8] ; Store initial r0
|
||||
STR r3, [r2, #12] ; Store initial r1
|
||||
STR r3, [r2, #16] ; Store initial r2
|
||||
STR r3, [r2, #20] ; Store initial r3
|
||||
STR r3, [r2, #24] ; Store initial r4
|
||||
STR r3, [r2, #28] ; Store initial r5
|
||||
STR r3, [r2, #32] ; Store initial r6
|
||||
STR r3, [r2, #36] ; Store initial r7
|
||||
STR r3, [r2, #40] ; Store initial r8
|
||||
STR r3, [r2, #44] ; Store initial r9
|
||||
LDR r3, [r0, #12] ; Pickup stack starting address
|
||||
STR r3, [r2, #48] ; Store initial r10 (sl)
|
||||
MOV r3, #0 ; Build initial register value
|
||||
STR r3, [r2, #52] ; Store initial r11
|
||||
STR r3, [r2, #56] ; Store initial r12
|
||||
STR r3, [r2, #60] ; Store initial lr
|
||||
STR r1, [r2, #64] ; Store initial pc
|
||||
STR r3, [r2, #68] ; 0 for back-trace
|
||||
MRS r1, CPSR ; Pickup CPSR
|
||||
BIC r1, r1, #CPSR_MASK ; Mask mode bits of CPSR
|
||||
ORR r3, r1, #SYS_MODE ; Build CPSR, SYS mode, interrupts enabled
|
||||
STR r3, [r2, #4] ; Store initial CPSR
|
||||
;
|
||||
; /* Setup stack pointer. */
|
||||
; thread_ptr -> tx_thread_stack_ptr = r2;
|
||||
;
|
||||
STR r2, [r0, #8] ; Save stack pointer in thread's
|
||||
; control block
|
||||
|
||||
BX lr ; Return to caller
|
||||
;}
|
||||
END
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _tx_timer_time_slice
|
||||
EXTERN _tx_thread_schedule
|
||||
EXTERN _tx_execution_thread_exit
|
||||
;
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_system_return Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function is target processor specific. It is used to transfer */
|
||||
;/* control from a thread back to the ThreadX system. Only a */
|
||||
;/* minimal context is saved since the compiler assumes temp registers */
|
||||
;/* are going to get slicked by a function call anyway. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* _tx_thread_schedule Thread scheduling loop */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ThreadX components */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_system_return(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_system_return
|
||||
ARM
|
||||
_tx_thread_system_return??rA
|
||||
_tx_thread_system_return
|
||||
;
|
||||
; /* Lockout interrupts. */
|
||||
;
|
||||
MRS r1, CPSR ; Pickup the CPSR
|
||||
CPSID i ; Disable interrupts
|
||||
; /* Save minimal context on the stack. */
|
||||
;
|
||||
STMDB sp!, {r4-r11, lr} ; Save minimal context
|
||||
LDR r5, =_tx_thread_current_ptr ; Pickup address of current ptr
|
||||
LDR r6, [r5, #0] ; Pickup current thread pointer
|
||||
|
||||
#ifdef __ARMVFP__
|
||||
LDR r0, [r6, #144] ; Pickup the VFP enabled flag
|
||||
CMP r0, #0 ; Is the VFP enabled?
|
||||
BEQ _tx_skip_solicited_vfp_save ; No, skip VFP solicited save
|
||||
VMRS r4, FPSCR ; Pickup the FPSCR
|
||||
STR r4, [sp, #-4]! ; Save FPSCR
|
||||
VSTMDB sp!, {D8-D15} ; Save D8-D15
|
||||
_tx_skip_solicited_vfp_save:
|
||||
#endif
|
||||
|
||||
MOV r0, #0 ; Build a solicited stack type
|
||||
STMDB sp!, {r0-r1} ; Save type and CPSR
|
||||
;
|
||||
;
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the thread exit function to indicate the thread is no longer executing. */
|
||||
;
|
||||
BL _tx_execution_thread_exit ; Call the thread exit function
|
||||
#endif
|
||||
|
||||
LDR r2, =_tx_timer_time_slice ; Pickup address of time slice
|
||||
LDR r1, [r2, #0] ; Pickup current time slice
|
||||
;
|
||||
; /* Save current stack and switch to system stack. */
|
||||
; _tx_thread_current_ptr -> tx_thread_stack_ptr = sp;
|
||||
; sp = _tx_thread_system_stack_ptr;
|
||||
;
|
||||
STR sp, [r6, #8] ; Save thread stack pointer
|
||||
;
|
||||
; /* Determine if the time-slice is active. */
|
||||
; if (_tx_timer_time_slice)
|
||||
; {
|
||||
;
|
||||
MOV r4, #0 ; Build clear value
|
||||
CMP r1, #0 ; Is a time-slice active?
|
||||
BEQ __tx_thread_dont_save_ts ; No, don't save the time-slice
|
||||
;
|
||||
; /* Save time-slice for the thread and clear the current time-slice. */
|
||||
; _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice;
|
||||
; _tx_timer_time_slice = 0;
|
||||
;
|
||||
STR r4, [r2, #0] ; Clear time-slice
|
||||
STR r1, [r6, #24] ; Save current time-slice
|
||||
;
|
||||
; }
|
||||
__tx_thread_dont_save_ts
|
||||
;
|
||||
; /* Clear the current thread pointer. */
|
||||
; _tx_thread_current_ptr = TX_NULL;
|
||||
;
|
||||
STR r4, [r5, #0] ; Clear current thread pointer
|
||||
B _tx_thread_schedule ; Jump to scheduler!
|
||||
;
|
||||
;}
|
||||
END
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
EXTERN _tx_thread_system_state
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _tx_execution_isr_enter
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_thread_vectored_context_save Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function saves the context of an executing thread in the */
|
||||
;/* beginning of interrupt processing. The function also ensures that */
|
||||
;/* the system stack is used upon return to the calling ISR. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* ISRs */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_thread_vectored_context_save(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_thread_vectored_context_save
|
||||
ARM
|
||||
_tx_thread_vectored_context_save
|
||||
;
|
||||
; /* Upon entry to this routine, it is assumed that IRQ interrupts are locked
|
||||
; out, we are in IRQ mode, the minimal context is already saved, and the
|
||||
; lr register contains the return ISR address. */
|
||||
;
|
||||
; /* Check for a nested interrupt condition. */
|
||||
; if (_tx_thread_system_state++)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_thread_system_state ; Pickup address of system state var
|
||||
LDR r2, [r3, #0] ; Pickup system state
|
||||
CMP r2, #0 ; Is this the first interrupt?
|
||||
BEQ __tx_thread_not_nested_save ; Yes, not a nested context save
|
||||
;
|
||||
; /* Nested interrupt condition. */
|
||||
;
|
||||
ADD r2, r2, #1 ; Increment the interrupt counter
|
||||
STR r2, [r3, #0] ; Store it back in the variable
|
||||
;
|
||||
; /* Note: Minimal context of interrupted thread is already saved. */
|
||||
;
|
||||
; /* Return to the ISR. */
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
BX lr ; Return to caller
|
||||
;
|
||||
__tx_thread_not_nested_save
|
||||
; }
|
||||
;
|
||||
; /* Otherwise, not nested, check to see if a thread was running. */
|
||||
; else if (_tx_thread_current_ptr)
|
||||
; {
|
||||
;
|
||||
ADD r2, r2, #1 ; Increment the interrupt counter
|
||||
STR r2, [r3, #0] ; Store it back in the variable
|
||||
LDR r1, =_tx_thread_current_ptr ; Pickup address of current thread ptr
|
||||
LDR r0, [r1, #0] ; Pickup current thread pointer
|
||||
CMP r0, #0 ; Is it NULL?
|
||||
BEQ __tx_thread_idle_system_save ; If so, interrupt occured in
|
||||
; scheduling loop - nothing needs saving!
|
||||
;
|
||||
; /* Note: Minimal context of interrupted thread is already saved. */
|
||||
;
|
||||
; /* Save the current stack pointer in the thread's control block. */
|
||||
; _tx_thread_current_ptr -> tx_stack_ptr = sp;
|
||||
;
|
||||
; /* Switch to the system stack. */
|
||||
; sp = _tx_thread_system_stack_ptr;
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
BX lr ; Return to caller
|
||||
;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
;
|
||||
__tx_thread_idle_system_save
|
||||
;
|
||||
; /* Interrupt occurred in the scheduling loop. */
|
||||
;
|
||||
; /* Not much to do here, just adjust the stack pointer, and return to IRQ
|
||||
; processing. */
|
||||
;
|
||||
MOV r10, #0 ; Clear stack limit
|
||||
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
;
|
||||
; /* Call the ISR enter function to indicate an ISR is executing. */
|
||||
;
|
||||
PUSH {lr} ; Save ISR lr
|
||||
BL _tx_execution_isr_enter ; Call the ISR enter function
|
||||
POP {lr} ; Recover ISR lr
|
||||
#endif
|
||||
|
||||
ADD sp, sp, #32 ; Recover saved registers
|
||||
MOV pc, lr ; Return to caller
|
||||
;
|
||||
; }
|
||||
;}
|
||||
END
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Timer */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;Define Assembly language external references...
|
||||
;
|
||||
EXTERN _tx_timer_time_slice
|
||||
EXTERN _tx_timer_system_clock
|
||||
EXTERN _tx_timer_current_ptr
|
||||
EXTERN _tx_timer_list_start
|
||||
EXTERN _tx_timer_list_end
|
||||
EXTERN _tx_timer_expired_time_slice
|
||||
EXTERN _tx_timer_expired
|
||||
EXTERN _tx_thread_time_slice
|
||||
EXTERN _tx_timer_expiration_process
|
||||
;
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _tx_timer_interrupt Cortex-R4/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* William E. Lamie, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function processes the hardware timer interrupt. This */
|
||||
;/* processing includes incrementing the system clock and checking for */
|
||||
;/* time slice and/or timer expiration. If either is found, the */
|
||||
;/* interrupt context save/restore functions are called along with the */
|
||||
;/* expiration functions. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* _tx_timer_expiration_process Timer expiration processing */
|
||||
;/* _tx_thread_time_slice Time-slice interrupted thread */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* interrupt vector */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 William E. Lamie Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _tx_timer_interrupt(VOID)
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _tx_timer_interrupt
|
||||
ARM
|
||||
_tx_timer_interrupt
|
||||
;
|
||||
; /* Upon entry to this routine, it is assumed that context save has already
|
||||
; been called, and therefore the compiler scratch registers are available
|
||||
; for use. */
|
||||
;
|
||||
; /* Increment the system clock. */
|
||||
; _tx_timer_system_clock++;
|
||||
;
|
||||
LDR r1, =_tx_timer_system_clock ; Pickup address of system clock
|
||||
LDR r0, [r1, #0] ; Pickup system clock
|
||||
ADD r0, r0, #1 ; Increment system clock
|
||||
STR r0, [r1, #0] ; Store new system clock
|
||||
;
|
||||
; /* Test for time-slice expiration. */
|
||||
; if (_tx_timer_time_slice)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_timer_time_slice ; Pickup address of time-slice
|
||||
LDR r2, [r3, #0] ; Pickup time-slice
|
||||
CMP r2, #0 ; Is it non-active?
|
||||
BEQ __tx_timer_no_time_slice ; Yes, skip time-slice processing
|
||||
;
|
||||
; /* Decrement the time_slice. */
|
||||
; _tx_timer_time_slice--;
|
||||
;
|
||||
SUB r2, r2, #1 ; Decrement the time-slice
|
||||
STR r2, [r3, #0] ; Store new time-slice value
|
||||
;
|
||||
; /* Check for expiration. */
|
||||
; if (__tx_timer_time_slice == 0)
|
||||
;
|
||||
CMP r2, #0 ; Has it expired?
|
||||
BNE __tx_timer_no_time_slice ; No, skip expiration processing
|
||||
;
|
||||
; /* Set the time-slice expired flag. */
|
||||
; _tx_timer_expired_time_slice = TX_TRUE;
|
||||
;
|
||||
LDR r3, =_tx_timer_expired_time_slice ; Pickup address of expired flag
|
||||
MOV r0, #1 ; Build expired value
|
||||
STR r0, [r3, #0] ; Set time-slice expiration flag
|
||||
;
|
||||
; }
|
||||
;
|
||||
__tx_timer_no_time_slice
|
||||
;
|
||||
; /* Test for timer expiration. */
|
||||
; if (*_tx_timer_current_ptr)
|
||||
; {
|
||||
;
|
||||
LDR r1, =_tx_timer_current_ptr ; Pickup current timer pointer addr
|
||||
LDR r0, [r1, #0] ; Pickup current timer
|
||||
LDR r2, [r0, #0] ; Pickup timer list entry
|
||||
CMP r2, #0 ; Is there anything in the list?
|
||||
BEQ __tx_timer_no_timer ; No, just increment the timer
|
||||
;
|
||||
; /* Set expiration flag. */
|
||||
; _tx_timer_expired = TX_TRUE;
|
||||
;
|
||||
LDR r3, =_tx_timer_expired ; Pickup expiration flag address
|
||||
MOV r2, #1 ; Build expired value
|
||||
STR r2, [r3, #0] ; Set expired flag
|
||||
B __tx_timer_done ; Finished timer processing
|
||||
;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
__tx_timer_no_timer
|
||||
;
|
||||
; /* No timer expired, increment the timer pointer. */
|
||||
; _tx_timer_current_ptr++;
|
||||
;
|
||||
ADD r0, r0, #4 ; Move to next timer
|
||||
;
|
||||
; /* Check for wrap-around. */
|
||||
; if (_tx_timer_current_ptr == _tx_timer_list_end)
|
||||
;
|
||||
LDR r3, =_tx_timer_list_end ; Pickup addr of timer list end
|
||||
LDR r2, [r3, #0] ; Pickup list end
|
||||
CMP r0, r2 ; Are we at list end?
|
||||
BNE __tx_timer_skip_wrap ; No, skip wrap-around logic
|
||||
;
|
||||
; /* Wrap to beginning of list. */
|
||||
; _tx_timer_current_ptr = _tx_timer_list_start;
|
||||
;
|
||||
LDR r3, =_tx_timer_list_start ; Pickup addr of timer list start
|
||||
LDR r0, [r3, #0] ; Set current pointer to list start
|
||||
;
|
||||
__tx_timer_skip_wrap
|
||||
;
|
||||
STR r0, [r1, #0] ; Store new current timer pointer
|
||||
; }
|
||||
;
|
||||
__tx_timer_done
|
||||
;
|
||||
;
|
||||
; /* See if anything has expired. */
|
||||
; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of expired flag
|
||||
LDR r2, [r3, #0] ; Pickup time-slice expired flag
|
||||
CMP r2, #0 ; Did a time-slice expire?
|
||||
BNE __tx_something_expired ; If non-zero, time-slice expired
|
||||
LDR r1, =_tx_timer_expired ; Pickup addr of other expired flag
|
||||
LDR r0, [r1, #0] ; Pickup timer expired flag
|
||||
CMP r0, #0 ; Did a timer expire?
|
||||
BEQ __tx_timer_nothing_expired ; No, nothing expired
|
||||
;
|
||||
__tx_something_expired
|
||||
;
|
||||
;
|
||||
STMDB sp!, {r0, lr} ; Save the lr register on the stack
|
||||
; and save r0 just to keep 8-byte alignment
|
||||
;
|
||||
; /* Did a timer expire? */
|
||||
; if (_tx_timer_expired)
|
||||
; {
|
||||
;
|
||||
LDR r1, =_tx_timer_expired ; Pickup addr of expired flag
|
||||
LDR r0, [r1, #0] ; Pickup timer expired flag
|
||||
CMP r0, #0 ; Check for timer expiration
|
||||
BEQ __tx_timer_dont_activate ; If not set, skip timer activation
|
||||
;
|
||||
; /* Process timer expiration. */
|
||||
; _tx_timer_expiration_process();
|
||||
;
|
||||
BL _tx_timer_expiration_process ; Call the timer expiration handling routine
|
||||
;
|
||||
; }
|
||||
__tx_timer_dont_activate
|
||||
;
|
||||
; /* Did time slice expire? */
|
||||
; if (_tx_timer_expired_time_slice)
|
||||
; {
|
||||
;
|
||||
LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of time-slice expired
|
||||
LDR r2, [r3, #0] ; Pickup the actual flag
|
||||
CMP r2, #0 ; See if the flag is set
|
||||
BEQ __tx_timer_not_ts_expiration ; No, skip time-slice processing
|
||||
;
|
||||
; /* Time slice interrupted thread. */
|
||||
; _tx_thread_time_slice();
|
||||
|
||||
BL _tx_thread_time_slice ; Call time-slice processing
|
||||
;
|
||||
; }
|
||||
;
|
||||
__tx_timer_not_ts_expiration
|
||||
;
|
||||
;
|
||||
LDMIA sp!, {r0, lr} ; Recover lr register (r0 is just there for
|
||||
; the 8-byte stack alignment
|
||||
;
|
||||
; }
|
||||
;
|
||||
__tx_timer_nothing_expired
|
||||
;
|
||||
BX lr ; Return to caller
|
||||
;
|
||||
;}
|
||||
END
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module Manager */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_power_of_two_block_size Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function calculates a power of two size at or immediately above*/
|
||||
/* the input size and returns it to the caller. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* size Block size */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* calculated size Rounded up to power of two */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _txm_module_manager_alignment_adjust Adjust alignment for Cortex-R */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
ULONG _txm_power_of_two_block_size(ULONG size)
|
||||
{
|
||||
/* Check for 0 size. */
|
||||
if(size == 0)
|
||||
return 0;
|
||||
|
||||
/* Minimum MPU block size is 32. */
|
||||
if(size <= 32)
|
||||
return 32;
|
||||
|
||||
/* Bit twiddling trick to round to next high power of 2
|
||||
(if original size is power of 2, it will return original size. Perfect!) */
|
||||
size--;
|
||||
size |= size >> 1;
|
||||
size |= size >> 2;
|
||||
size |= size >> 4;
|
||||
size |= size >> 8;
|
||||
size |= size >> 16;
|
||||
size++;
|
||||
|
||||
/* Return a power of 2 size at or above the input size. */
|
||||
return(size);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_alignment_adjust Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function adjusts the alignment and size of the code and data */
|
||||
/* section for a given module implementation. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* module_preamble Pointer to module preamble */
|
||||
/* code_size Size of the code area (updated) */
|
||||
/* code_alignment Code area alignment (updated) */
|
||||
/* data_size Size of data area (updated) */
|
||||
/* data_alignment Data area alignment (updated) */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _txm_power_of_two_block_size Calculate power of two size */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Initial thread stack frame */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _txm_module_manager_alignment_adjust(TXM_MODULE_PREAMBLE *module_preamble,
|
||||
ULONG *code_size,
|
||||
ULONG *code_alignment,
|
||||
ULONG *data_size,
|
||||
ULONG *data_alignment)
|
||||
{
|
||||
|
||||
ULONG local_code_size;
|
||||
ULONG local_code_alignment;
|
||||
ULONG local_data_size;
|
||||
ULONG local_data_alignment;
|
||||
ULONG code_size_accum;
|
||||
ULONG data_size_accum;
|
||||
|
||||
/* Copy the input parameters into local variables for ease of use. */
|
||||
local_code_size = *code_size;
|
||||
local_code_alignment = *code_alignment;
|
||||
local_data_size = *data_size;
|
||||
local_data_alignment = *data_alignment;
|
||||
|
||||
/* Determine code block sizes. Minimize the alignment requirement.
|
||||
There are 4 MPU code entries available. The following is how the code size
|
||||
will be distributed:
|
||||
1. 1/4 of the largest power of two that is greater than or equal to code size.
|
||||
2. 1/4 of the largest power of two that is greater than or equal to code size.
|
||||
3. Largest power of 2 that fits in the remaining space.
|
||||
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
local_code_alignment = _txm_power_of_two_block_size(local_code_size) >> 2;
|
||||
code_size_accum = local_code_alignment + local_code_alignment;
|
||||
code_size_accum = code_size_accum + (_txm_power_of_two_block_size(local_code_size - code_size_accum) >> 1);
|
||||
code_size_accum = code_size_accum + _txm_power_of_two_block_size(local_code_size - code_size_accum);
|
||||
local_code_size = code_size_accum;
|
||||
|
||||
/* Determine data block sizes. Minimize the alignment requirement.
|
||||
There are 4 MPU data entries available. The following is how the data size
|
||||
will be distributed:
|
||||
1. 1/4 of the largest power of two that is greater than or equal to data size.
|
||||
2. 1/4 of the largest power of two that is greater than or equal to data size.
|
||||
3. Largest power of 2 that fits in the remaining space.
|
||||
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
local_data_alignment = _txm_power_of_two_block_size(local_data_size) >> 2;
|
||||
data_size_accum = local_data_alignment + local_data_alignment;
|
||||
data_size_accum = data_size_accum + (_txm_power_of_two_block_size(local_data_size - data_size_accum) >> 1);
|
||||
data_size_accum = data_size_accum + _txm_power_of_two_block_size(local_data_size - data_size_accum);
|
||||
local_data_size = data_size_accum;
|
||||
|
||||
/* Return all the information to the caller. */
|
||||
*code_size = local_code_size;
|
||||
*code_alignment = local_code_alignment;
|
||||
*data_size = local_data_size;
|
||||
*data_alignment = local_data_alignment;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module Manager */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_mutex.h"
|
||||
#include "tx_queue.h"
|
||||
#include "tx_thread.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_external_memory_enable Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function adds an entry in the MPU table for a shared */
|
||||
/* memory space. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* module_instance Module instance pointer */
|
||||
/* start_address Start address of memory */
|
||||
/* length Length of external memory */
|
||||
/* attributes Memory attributes (r/w) */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_mutex_get Get protection mutex */
|
||||
/* _tx_mutex_put Release protection mutex */
|
||||
/* _txm_power_of_two_block_size Round length to power of two */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _txm_module_manager_external_memory_enable(TXM_MODULE_INSTANCE *module_instance,
|
||||
VOID *start_address,
|
||||
ULONG length,
|
||||
UINT attributes)
|
||||
{
|
||||
|
||||
ULONG block_size;
|
||||
ULONG region_size;
|
||||
ULONG srd_bits;
|
||||
ULONG size_register;
|
||||
ULONG address;
|
||||
ULONG shared_index;
|
||||
ULONG attributes_check = 0;
|
||||
|
||||
/* Determine if the module manager has been initialized. */
|
||||
if (_txm_module_manager_ready != TX_TRUE)
|
||||
{
|
||||
/* Module manager has not been initialized. */
|
||||
return(TX_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
/* Determine if the module is valid. */
|
||||
if (module_instance == TX_NULL)
|
||||
{
|
||||
/* Invalid module pointer. */
|
||||
return(TX_PTR_ERROR);
|
||||
}
|
||||
|
||||
/* Get module manager protection mutex. */
|
||||
_tx_mutex_get(&_txm_module_manager_mutex, TX_WAIT_FOREVER);
|
||||
|
||||
/* Determine if the module instance is valid. */
|
||||
if (module_instance -> txm_module_instance_id != TXM_MODULE_ID)
|
||||
{
|
||||
/* Release the protection mutex. */
|
||||
_tx_mutex_put(&_txm_module_manager_mutex);
|
||||
|
||||
/* Invalid module pointer. */
|
||||
return(TX_PTR_ERROR);
|
||||
}
|
||||
|
||||
/* Determine if the module instance is in the loaded state. */
|
||||
if (module_instance -> txm_module_instance_state != TXM_MODULE_LOADED)
|
||||
{
|
||||
/* Release the protection mutex. */
|
||||
_tx_mutex_put(&_txm_module_manager_mutex);
|
||||
|
||||
/* Return error if the module is not ready. */
|
||||
return(TX_START_ERROR);
|
||||
}
|
||||
|
||||
/* Determine if there are shared memory entries available. */
|
||||
if(module_instance -> txm_module_instance_shared_memory_count >= TXM_MODULE_MPU_SHARED_ENTRIES)
|
||||
{
|
||||
/* Release the protection mutex. */
|
||||
_tx_mutex_put(&_txm_module_manager_mutex);
|
||||
|
||||
/* No more entries available. */
|
||||
return(TX_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Start address and length must adhere to Cortex-R MPU.
|
||||
The address must align with the block size. */
|
||||
|
||||
block_size = _txm_power_of_two_block_size(length);
|
||||
address = (ULONG) start_address;
|
||||
if(address != (address & ~(block_size - 1)))
|
||||
{
|
||||
/* Release the protection mutex. */
|
||||
_tx_mutex_put(&_txm_module_manager_mutex);
|
||||
|
||||
/* Return alignment error. */
|
||||
return(TXM_MODULE_ALIGNMENT_ERROR);
|
||||
}
|
||||
|
||||
/* At this point, we have a valid address and block size.
|
||||
Set up MPU registers. */
|
||||
|
||||
/* Generate index into shared memory entries. */
|
||||
shared_index = TXM_MODULE_MPU_SHARED_INDEX + module_instance -> txm_module_instance_shared_memory_count;
|
||||
|
||||
/* Save address register. */
|
||||
module_instance -> txm_module_instance_mpu_registers[shared_index].txm_module_mpu_region_address = address;
|
||||
|
||||
/* Calculate the region size. */
|
||||
region_size = (_txm_module_manager_region_size_get(block_size) << 1);
|
||||
/* Calculate the subregion bits. */
|
||||
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, length);
|
||||
|
||||
/* Save size register. */
|
||||
size_register = srd_bits | region_size | TXM_ENABLE_REGION;
|
||||
module_instance -> txm_module_instance_mpu_registers[shared_index].txm_module_mpu_region_size = size_register;
|
||||
|
||||
/* Check for optional attributes. */
|
||||
if(attributes & TXM_MODULE_MANAGER_SHARED_ATTRIBUTE_WRITE)
|
||||
{
|
||||
attributes_check = TXM_MODULE_MANAGER_ATTRIBUTE_WRITE_MPU_BIT;
|
||||
}
|
||||
|
||||
/* Save attributes register. */
|
||||
module_instance -> txm_module_instance_mpu_registers[shared_index].txm_module_mpu_region_attributes = attributes_check | TXM_MODULE_MPU_SHARED_ACCESS_CONTROL;
|
||||
|
||||
/* Keep track of shared memory address and length in module instance. */
|
||||
module_instance -> txm_module_instance_shared_memory_address[module_instance -> txm_module_instance_shared_memory_count] = address;
|
||||
module_instance -> txm_module_instance_shared_memory_length[module_instance -> txm_module_instance_shared_memory_count] = length;
|
||||
|
||||
/* Increment counter. */
|
||||
module_instance -> txm_module_instance_shared_memory_count++;
|
||||
|
||||
/* Release the protection mutex. */
|
||||
_tx_mutex_put(&_txm_module_manager_mutex);
|
||||
|
||||
/* Return success. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module Manager */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
|
||||
/* Define the user's fault notification callback function pointer. This is
|
||||
setup via the txm_module_manager_memory_fault_notify API. */
|
||||
|
||||
VOID (*_txm_module_manager_fault_notify)(TX_THREAD *, TXM_MODULE_INSTANCE *);
|
||||
|
||||
|
||||
/* Define a macro that can be used to allocate global variables useful to
|
||||
store information about the last fault. This macro is defined in
|
||||
txm_module_port.h and is usually populated in the assembly language
|
||||
fault handling prior to the code calling _txm_module_manager_memory_fault_handler. */
|
||||
|
||||
TXM_MODULE_MANAGER_FAULT_INFO
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_memory_fault_handler Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function handles a fault associated with a memory protected */
|
||||
/* module. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_terminate Terminate thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Fault handler */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _txm_module_manager_memory_fault_handler(VOID)
|
||||
{
|
||||
|
||||
TXM_MODULE_INSTANCE *module_instance_ptr;
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
|
||||
/* Pickup the current thread. */
|
||||
thread_ptr = _tx_thread_current_ptr;
|
||||
|
||||
/* Initialize the module instance pointer to NULL. */
|
||||
module_instance_ptr = TX_NULL;
|
||||
|
||||
/* Is there a thread? */
|
||||
if (thread_ptr)
|
||||
{
|
||||
/* Pickup the module instance. */
|
||||
module_instance_ptr = thread_ptr -> tx_thread_module_instance_ptr;
|
||||
|
||||
/* Terminate the current thread. */
|
||||
_tx_thread_terminate(_tx_thread_current_ptr);
|
||||
}
|
||||
|
||||
/* Determine if there is a user memory fault notification callback. */
|
||||
if (_txm_module_manager_fault_notify)
|
||||
{
|
||||
/* Yes, call the user's notification memory fault callback. */
|
||||
(_txm_module_manager_fault_notify)(thread_ptr, module_instance_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module Manager */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
|
||||
/* Define the external user's fault notification callback function pointer. This is
|
||||
setup via the txm_module_manager_memory_fault_notify API. */
|
||||
|
||||
extern VOID (*_txm_module_manager_fault_notify)(TX_THREAD *, TXM_MODULE_INSTANCE *);
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_memory_fault_notify Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application callback when/if a memory */
|
||||
/* fault occurs. The supplied thread is automatically terminated, but */
|
||||
/* any other threads in the same module may still execute. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* notify_function Memory fault notification */
|
||||
/* function, NULL disables. */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _txm_module_manager_memory_fault_notify(VOID (*notify_function)(TX_THREAD *, TXM_MODULE_INSTANCE *))
|
||||
{
|
||||
/* Setup notification function. */
|
||||
_txm_module_manager_fault_notify = notify_function;
|
||||
|
||||
/* Return success. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Module Manager */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "txm_module.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_region_size_get Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function converts the region size in bytes to the block size */
|
||||
/* for the Cortex-R4 MPU specification. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* block_size Size of the block in bytes */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* MPU size specification */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _txm_module_manager_mm_register_setup */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
ULONG _txm_module_manager_region_size_get(ULONG block_size)
|
||||
{
|
||||
|
||||
ULONG return_value;
|
||||
|
||||
/* Process relative to the input block size. */
|
||||
if (block_size == 32)
|
||||
{
|
||||
return_value = 0x04;
|
||||
}
|
||||
else if (block_size == 64)
|
||||
{
|
||||
return_value = 0x05;
|
||||
}
|
||||
else if (block_size == 128)
|
||||
{
|
||||
return_value = 0x06;
|
||||
}
|
||||
else if (block_size == 256)
|
||||
{
|
||||
return_value = 0x07;
|
||||
}
|
||||
else if (block_size == 512)
|
||||
{
|
||||
return_value = 0x08;
|
||||
}
|
||||
else if (block_size == 1024)
|
||||
{
|
||||
return_value = 0x09;
|
||||
}
|
||||
else if (block_size == 2048)
|
||||
{
|
||||
return_value = 0x0A;
|
||||
}
|
||||
else if (block_size == 4096)
|
||||
{
|
||||
return_value = 0x0B;
|
||||
}
|
||||
else if (block_size == 8192)
|
||||
{
|
||||
return_value = 0x0C;
|
||||
}
|
||||
else if (block_size == 16384)
|
||||
{
|
||||
return_value = 0x0D;
|
||||
}
|
||||
else if (block_size == 32768)
|
||||
{
|
||||
return_value = 0x0E;
|
||||
}
|
||||
else if (block_size == 65536)
|
||||
{
|
||||
return_value = 0x0F;
|
||||
}
|
||||
else if (block_size == 131072)
|
||||
{
|
||||
return_value = 0x10;
|
||||
}
|
||||
else if (block_size == 262144)
|
||||
{
|
||||
return_value = 0x11;
|
||||
}
|
||||
else if (block_size == 524288)
|
||||
{
|
||||
return_value = 0x12;
|
||||
}
|
||||
else if (block_size == 1048576)
|
||||
{
|
||||
return_value = 0x13;
|
||||
}
|
||||
else if (block_size == 2097152)
|
||||
{
|
||||
return_value = 0x14;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Max 4MB MPU pages for modules. */
|
||||
return_value = 0x15;
|
||||
}
|
||||
|
||||
return(return_value);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_calculate_srd_bits Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function calculates the SRD bits that need to be set to */
|
||||
/* protect "length" bytes in a block. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* block_size Size of the block in bytes */
|
||||
/* length Actual length in bytes */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* SRD bits to be OR'ed with region attribute register. */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _txm_module_manager_mm_register_setup */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
ULONG _txm_module_manager_calculate_srd_bits(ULONG block_size, ULONG length)
|
||||
{
|
||||
|
||||
ULONG srd_bits = 0;
|
||||
UINT srd_bit_index;
|
||||
|
||||
/* length is smaller than block_size, set SRD bits if block_size is 256 or more. */
|
||||
if((block_size >= 256) && (length < block_size))
|
||||
{
|
||||
/* Divide block_size by 8 by shifting right 3. Result is size of subregion. */
|
||||
block_size = block_size >> 3;
|
||||
|
||||
/* Set SRD index into attribute register. */
|
||||
srd_bit_index = 8;
|
||||
|
||||
/* If subregion overlaps length, move to the next subregion. */
|
||||
while(length > block_size)
|
||||
{
|
||||
length = length - block_size;
|
||||
srd_bit_index++;
|
||||
}
|
||||
|
||||
/* Check for a portion of code remaining. */
|
||||
if(length)
|
||||
{
|
||||
srd_bit_index++;
|
||||
}
|
||||
|
||||
/* Set unused subregion bits. */
|
||||
while(srd_bit_index < 16)
|
||||
{
|
||||
srd_bits = srd_bits | (0x1 << srd_bit_index);
|
||||
srd_bit_index++;
|
||||
}
|
||||
}
|
||||
|
||||
return(srd_bits);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_mm_register_setup Cortex-R4/MPU/IAR */
|
||||
/* 6.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function sets up the MPU register definitions based on the */
|
||||
/* module's memory characteristics. */
|
||||
/* MPU layout for the Cortex-R4: */
|
||||
/* Entry Description */
|
||||
/* 0 Kernel mode entry */
|
||||
/* 1 Module code region */
|
||||
/* 2 Module code region */
|
||||
/* 3 Module code region */
|
||||
/* 4 Module code region */
|
||||
/* 5 Module data region */
|
||||
/* 6 Module data region */
|
||||
/* 7 Module data region */
|
||||
/* 8 Module data region */
|
||||
/* 9 Module shared memory region */
|
||||
/* 10 Module shared memory region */
|
||||
/* 11 Module shared memory region */
|
||||
/* */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* module_instance Pointer to module instance */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* MPU specifications for module in module_instance */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _txm_module_manager_region_size_get */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _txm_module_manager_thread_create */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _txm_module_manager_mm_register_setup(TXM_MODULE_INSTANCE *module_instance)
|
||||
{
|
||||
|
||||
ULONG code_address;
|
||||
ULONG code_size;
|
||||
ULONG data_address;
|
||||
ULONG data_size;
|
||||
ULONG start_stop_stack_size;
|
||||
ULONG callback_stack_size;
|
||||
ULONG block_size;
|
||||
ULONG base_address_register;
|
||||
ULONG size_register;
|
||||
ULONG region_size;
|
||||
ULONG srd_bits = 0;
|
||||
UINT mpu_table_index;
|
||||
UINT i;
|
||||
|
||||
|
||||
/* Setup the first region for kernel mode entry. */
|
||||
|
||||
/* Set address register to user mode entry function address, which is guaranteed to be at least 32-byte aligned. */
|
||||
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_address = (ULONG) _txm_module_manager_user_mode_entry;
|
||||
|
||||
/* Set the size (32 bytes) and enable bit. */
|
||||
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_size = (_txm_module_manager_region_size_get(32) << 1) | TXM_ENABLE_REGION;
|
||||
|
||||
/* Set attributes. */
|
||||
module_instance -> txm_module_instance_mpu_registers[TXM_MODULE_MPU_KERNEL_ENTRY_INDEX].txm_module_mpu_region_attributes = TXM_MODULE_MPU_CODE_ACCESS_CONTROL;
|
||||
|
||||
/* End of kernel mode entry setup. */
|
||||
|
||||
/* Setup code protection. */
|
||||
|
||||
/* Initialize the MPU table index. */
|
||||
mpu_table_index = 1;
|
||||
|
||||
/* Pickup code starting address and actual size. */
|
||||
code_address = (ULONG) module_instance -> txm_module_instance_code_start;
|
||||
code_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_code_size;
|
||||
|
||||
/* Determine code block sizes. Minimize the alignment requirement.
|
||||
There are 4 MPU code entries available. The following is how the code size
|
||||
will be distributed:
|
||||
1. 1/4 of the largest power of two that is greater than or equal to code size.
|
||||
2. 1/4 of the largest power of two that is greater than or equal to code size.
|
||||
3. Largest power of 2 that fits in the remaining space.
|
||||
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
|
||||
/* Now loop through to setup MPU protection for the code area. */
|
||||
for (i = 0; i < TXM_MODULE_MPU_CODE_ENTRIES; i++)
|
||||
{
|
||||
/* First two MPU blocks are 1/4 of the largest power of two
|
||||
that is greater than or equal to code size. */
|
||||
if (i < 2)
|
||||
{
|
||||
block_size = _txm_power_of_two_block_size(code_size) >> 2;
|
||||
}
|
||||
|
||||
/* Third MPU block is the largest power of 2 that fits in the remaining space. */
|
||||
else if (i == 2)
|
||||
{
|
||||
/* Subtract (block_size*2) from code_size to calculate remaining space. */
|
||||
code_size = code_size - (block_size << 1);
|
||||
block_size = _txm_power_of_two_block_size(code_size) >> 1;
|
||||
}
|
||||
|
||||
/* Last MPU block is the smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
else
|
||||
{
|
||||
/* Calculate remaining space. */
|
||||
code_size = code_size - block_size;
|
||||
block_size = _txm_power_of_two_block_size(code_size);
|
||||
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, code_size);
|
||||
}
|
||||
|
||||
/* Build the base address register. */
|
||||
base_address_register = (code_address & ~(block_size - 1));
|
||||
|
||||
/* Calculate the region size information. */
|
||||
region_size = (_txm_module_manager_region_size_get(block_size) << 1);
|
||||
|
||||
/* Build the size register. */
|
||||
size_register = srd_bits | region_size | TXM_ENABLE_REGION;
|
||||
|
||||
/* Setup the MPU address, size, and attribute registers. */
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = base_address_register;
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_size = size_register;
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attributes = TXM_MODULE_MPU_CODE_ACCESS_CONTROL;
|
||||
|
||||
/* Adjust the code address. */
|
||||
code_address = code_address + block_size;
|
||||
|
||||
/* Increment MPU table index. */
|
||||
mpu_table_index++;
|
||||
}
|
||||
/* End of code protection. */
|
||||
|
||||
/* Setup data protection. */
|
||||
|
||||
/* Reset SRD bitfield. */
|
||||
srd_bits = 0;
|
||||
|
||||
/* Pickup data starting address and actual size. */
|
||||
data_address = (ULONG) module_instance -> txm_module_instance_data_start;
|
||||
|
||||
/* Adjust the size of the module elements to be aligned to the default alignment. We do this
|
||||
so that when we partition the allocated memory, we can simply place these regions right beside
|
||||
each other without having to align their pointers. Note this only works when they all have
|
||||
the same alignment. */
|
||||
|
||||
data_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_data_size;
|
||||
start_stop_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_start_stop_stack_size;
|
||||
callback_stack_size = module_instance -> txm_module_instance_preamble_ptr -> txm_module_preamble_callback_stack_size;
|
||||
|
||||
data_size = ((data_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
|
||||
|
||||
start_stop_stack_size = ((start_stop_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
|
||||
|
||||
callback_stack_size = ((callback_stack_size + TXM_MODULE_DATA_ALIGNMENT - 1)/TXM_MODULE_DATA_ALIGNMENT) * TXM_MODULE_DATA_ALIGNMENT;
|
||||
|
||||
/* Update the data size to include thread stacks. */
|
||||
data_size = data_size + start_stop_stack_size + callback_stack_size;
|
||||
|
||||
/* Determine data block sizes. Minimize the alignment requirement.
|
||||
There are 4 MPU data entries available. The following is how the data size
|
||||
will be distributed:
|
||||
1. 1/4 of the largest power of two that is greater than or equal to data size.
|
||||
2. 1/4 of the largest power of two that is greater than or equal to data size.
|
||||
3. Largest power of 2 that fits in the remaining space.
|
||||
4. Smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
|
||||
/* Now loop through to setup MPU protection for the data area. */
|
||||
for (i = 0; i < TXM_MODULE_MPU_DATA_ENTRIES; i++)
|
||||
{
|
||||
/* First two MPU blocks are 1/4 of the largest power of two
|
||||
that is greater than or equal to data size. */
|
||||
if (i < 2)
|
||||
{
|
||||
block_size = _txm_power_of_two_block_size(data_size) >> 2;
|
||||
}
|
||||
|
||||
/* Third MPU block is the largest power of 2 that fits in the remaining space. */
|
||||
else if (i == 2)
|
||||
{
|
||||
/* Subtract (block_size*2) from data_size to calculate remaining space. */
|
||||
data_size = data_size - (block_size << 1);
|
||||
block_size = _txm_power_of_two_block_size(data_size) >> 1;
|
||||
}
|
||||
|
||||
/* Last MPU block is the smallest power of 2 that exceeds the remaining space, minimum 32. */
|
||||
else
|
||||
{
|
||||
/* Calculate remaining space. */
|
||||
data_size = data_size - block_size;
|
||||
block_size = _txm_power_of_two_block_size(data_size);
|
||||
srd_bits = _txm_module_manager_calculate_srd_bits(block_size, data_size);
|
||||
}
|
||||
|
||||
/* Build the base address register. */
|
||||
base_address_register = (data_address & ~(block_size - 1));
|
||||
|
||||
/* Calculate the region size information. */
|
||||
region_size = (_txm_module_manager_region_size_get(block_size) << 1);
|
||||
|
||||
/* Build the size register. */
|
||||
size_register = srd_bits | region_size | TXM_ENABLE_REGION;
|
||||
|
||||
/* Setup the MPU address, size, and attribute registers. */
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_address = base_address_register;
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_size = size_register;
|
||||
module_instance -> txm_module_instance_mpu_registers[mpu_table_index].txm_module_mpu_region_attributes = TXM_MODULE_MPU_DATA_ACCESS_CONTROL;
|
||||
|
||||
/* Adjust the data address. */
|
||||
data_address = data_address + block_size;
|
||||
|
||||
/* Increment MPU table index. */
|
||||
mpu_table_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _txm_module_manager_inside_data_check Cortex-R4/MPU/IAR */
|
||||
/* 6.1.6 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* Scott Larson, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function checks if the specified object is inside shared */
|
||||
/* memory. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* module_instance Pointer to module instance */
|
||||
/* obj_ptr Pointer to the object */
|
||||
/* obj_size Size of the object */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* Whether the object is inside the shared memory region. */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* N/A */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Module dispatch check functions */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
/* 04-02-2021 Scott Larson Modified comments, added */
|
||||
/* check for overflow, *
|
||||
/* resulting in version 6.1.6 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _txm_module_manager_inside_data_check(TXM_MODULE_INSTANCE *module_instance, ALIGN_TYPE obj_ptr, UINT obj_size)
|
||||
{
|
||||
|
||||
UINT shared_memory_index;
|
||||
UINT num_shared_memory_mpu_entries;
|
||||
ALIGN_TYPE shared_memory_address_start;
|
||||
ALIGN_TYPE shared_memory_address_end;
|
||||
|
||||
/* Check for overflow. */
|
||||
if ((obj_ptr) > ((obj_ptr) + (obj_size)))
|
||||
{
|
||||
return(TX_FALSE);
|
||||
}
|
||||
|
||||
/* Check if the object is inside the module data. */
|
||||
if ((obj_ptr >= (ALIGN_TYPE) module_instance -> txm_module_instance_data_start) &&
|
||||
((obj_ptr + obj_size) <= ((ALIGN_TYPE) module_instance -> txm_module_instance_data_end + 1)))
|
||||
{
|
||||
return(TX_TRUE);
|
||||
}
|
||||
|
||||
/* Check if the object is inside the shared memory. */
|
||||
num_shared_memory_mpu_entries = module_instance -> txm_module_instance_shared_memory_count;
|
||||
for (shared_memory_index = 0; shared_memory_index < num_shared_memory_mpu_entries; shared_memory_index++)
|
||||
{
|
||||
|
||||
shared_memory_address_start = (ALIGN_TYPE) module_instance -> txm_module_instance_shared_memory_address[shared_memory_index];
|
||||
shared_memory_address_end = shared_memory_address_start + module_instance -> txm_module_instance_shared_memory_length[shared_memory_index];
|
||||
|
||||
if ((obj_ptr >= (ALIGN_TYPE) shared_memory_address_start) &&
|
||||
((obj_ptr + obj_size) <= (ALIGN_TYPE) shared_memory_address_end))
|
||||
{
|
||||
return(TX_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return(TX_FALSE);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
THUMB_MASK DEFINE 0x20 ; THUMB bit
|
||||
USR_MODE DEFINE 0x10 ; USR mode
|
||||
SYS_MODE DEFINE 0x1F ; SYS mode
|
||||
CPSR_MASK DEFINE 0xBF ; Mask initial CPSR, IRQ ints enabled
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _txm_module_manager_thread_stack_build Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function builds a stack frame on the supplied thread's stack. */
|
||||
;/* The stack frame results in a fake interrupt return to the supplied */
|
||||
;/* function pointer. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* thread_ptr Pointer to thread control blk */
|
||||
;/* function_ptr Pointer to return function */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* _tx_thread_create Create thread service */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;VOID _txm_module_manager_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(TX_THREAD *, TXM_MODULE_INSTANCE *))
|
||||
;{
|
||||
RSEG .text:CODE:NOROOT(2)
|
||||
PUBLIC _txm_module_manager_thread_stack_build
|
||||
ARM
|
||||
_txm_module_manager_thread_stack_build
|
||||
;
|
||||
;
|
||||
; /* Build a fake interrupt frame. The form of the fake interrupt stack
|
||||
; on the Cortex-R4 should look like the following after it is built:
|
||||
;
|
||||
; Stack Top: 1 Interrupt stack frame type
|
||||
; CPSR Initial value for CPSR
|
||||
; r0 Initial value for r0
|
||||
; r1 Initial value for r1
|
||||
; r2 Initial value for r2
|
||||
; r3 Initial value for r3
|
||||
; r4 Initial value for r4
|
||||
; r5 Initial value for r5
|
||||
; r6 Initial value for r6
|
||||
; r7 Initial value for r7
|
||||
; r8 Initial value for r8
|
||||
; r9 Initial value for r9
|
||||
; r10 Initial value for r10
|
||||
; r11 Initial value for r11
|
||||
; r12 Initial value for r12
|
||||
; lr Initial value for lr (r14)
|
||||
; pc Initial value for pc (r15)
|
||||
; 0 For stack backtracing
|
||||
;
|
||||
; Stack Bottom: (higher memory address) */
|
||||
;
|
||||
LDR r2, [r0, #16] ; Pickup end of stack area
|
||||
BIC r2, r2, #7 ; Ensure 8-byte alignment
|
||||
SUB r2, r2, #76 ; Allocate space for the stack frame
|
||||
;
|
||||
; /* Actually build the stack frame. */
|
||||
;
|
||||
MOV r3, #1 ; Build interrupt stack type
|
||||
STR r3, [r2, #0] ; Store stack type
|
||||
STR r0, [r2, #8] ; Store initial r0 (thread pointer)
|
||||
LDR r3, [r0, #8] ; Pickup thread info pointer (it's in the stack pointer location right now)
|
||||
STR r3, [r2, #12] ; Store initial r1
|
||||
LDR r3, [r3, #8] ; Pickup data base register
|
||||
STR r3, [r2, #44] ; Store initial r9
|
||||
MOV r3, #0 ; Build initial register value
|
||||
STR r3, [r2, #16] ; Store initial r2
|
||||
STR r3, [r2, #20] ; Store initial r3
|
||||
STR r3, [r2, #24] ; Store initial r4
|
||||
STR r3, [r2, #28] ; Store initial r5
|
||||
STR r3, [r2, #32] ; Store initial r6
|
||||
STR r3, [r2, #36] ; Store initial r7
|
||||
STR r3, [r2, #40] ; Store initial r8
|
||||
LDR r3, [r0, #12] ; Pickup stack starting address
|
||||
STR r3, [r2, #48] ; Store initial r10 (sl)
|
||||
MOV r3, #0 ; Build initial register value
|
||||
STR r3, [r2, #52] ; Store initial r11
|
||||
STR r3, [r2, #56] ; Store initial r12
|
||||
STR r3, [r2, #60] ; Store initial lr
|
||||
STR r1, [r2, #64] ; Store initial pc
|
||||
STR r3, [r2, #68] ; 0 for back-trace
|
||||
MRS r3, CPSR ; Pickup CPSR
|
||||
BIC r3, r3, #CPSR_MASK ; Mask mode bits of CPSR
|
||||
TST r1, #1 ; Test if THUMB bit set in initial PC
|
||||
ORRNE r3, r3, #THUMB_MASK ; Set T bit if set
|
||||
LDR r1, [r0, #156] ; Load tx_thread_module_user_mode
|
||||
TST r1, #1 ; Test if the user mode flag is set
|
||||
ORREQ r3, r3, #SYS_MODE ; Flag not set: Build CPSR, SYS mode, IRQ enabled
|
||||
ORRNE r3, r3, #USR_MODE ; Flag set: Build CPSR, USR mode, IRQ enabled
|
||||
STR r3, [r2, #4] ; Store initial CPSR
|
||||
;
|
||||
; /* Setup stack pointer. */
|
||||
; thread_ptr -> tx_thread_stack_ptr = r2;
|
||||
;
|
||||
STR r2, [r0, #8] ; Save stack pointer in thread's control block
|
||||
BX lr ; Return to caller
|
||||
;}
|
||||
END
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
;/* */
|
||||
;/* This software is licensed under the Microsoft Software License */
|
||||
;/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
;/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
;/* and in the root directory of this software. */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
;
|
||||
;
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;/** */
|
||||
;/** ThreadX Component */
|
||||
;/** */
|
||||
;/** Thread */
|
||||
;/** */
|
||||
;/**************************************************************************/
|
||||
;/**************************************************************************/
|
||||
;
|
||||
EXTERN _tx_thread_current_ptr
|
||||
EXTERN _txm_module_manager_kernel_dispatch
|
||||
|
||||
|
||||
RSEG .text:CODE:NOROOT(5)
|
||||
ARM
|
||||
;/**************************************************************************/
|
||||
;/* */
|
||||
;/* FUNCTION RELEASE */
|
||||
;/* */
|
||||
;/* _txm_module_manager_user_mode_entry Cortex-R4/MPU/IAR */
|
||||
;/* 6.1 */
|
||||
;/* AUTHOR */
|
||||
;/* */
|
||||
;/* Scott Larson, Microsoft Corporation */
|
||||
;/* */
|
||||
;/* DESCRIPTION */
|
||||
;/* */
|
||||
;/* This function allows modules to enter kernel mode. */
|
||||
;/* */
|
||||
;/* INPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* OUTPUT */
|
||||
;/* */
|
||||
;/* None */
|
||||
;/* */
|
||||
;/* CALLS */
|
||||
;/* */
|
||||
;/* SVC 1 Enter kernel mode */
|
||||
;/* SVC 2 Exit kernel mode */
|
||||
;/* */
|
||||
;/* CALLED BY */
|
||||
;/* */
|
||||
;/* Modules in user mode */
|
||||
;/* */
|
||||
;/* RELEASE HISTORY */
|
||||
;/* */
|
||||
;/* DATE NAME DESCRIPTION */
|
||||
;/* */
|
||||
;/* 09-30-2020 Scott Larson Initial Version 6.1 */
|
||||
;/* */
|
||||
;/**************************************************************************/
|
||||
PUBLIC _txm_module_manager_user_mode_entry
|
||||
_txm_module_manager_user_mode_entry:
|
||||
|
||||
EXPORT _txm_system_mode_enter
|
||||
_txm_system_mode_enter
|
||||
SVC 1 ; Get out of user mode
|
||||
_txm_module_priv
|
||||
; At this point, we are in system mode.
|
||||
; Save LR (and r3 for 8 byte aligned stack) and call the kernel dispatch function.
|
||||
PUSH {r3, lr}
|
||||
BL _txm_module_manager_kernel_dispatch
|
||||
POP {r3, lr}
|
||||
|
||||
EXPORT _txm_system_mode_exit
|
||||
_txm_system_mode_exit
|
||||
; Trap to restore user mode while inside of ThreadX
|
||||
SVC 2
|
||||
|
||||
BX lr ; Return to the caller
|
||||
NOP
|
||||
NOP
|
||||
_txm_module_manager_user_mode_end
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user