summaryrefslogtreecommitdiff
path: root/test/tx/cmake/module_qemu/tests/module_services.c
blob: e2fcce44b0bf70dce2150e0620d1ef691074b994 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/***************************************************************************
 * Copyright (c) 2026 Eclipse ThreadX contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * AI Disclosure: This file was largely AI-generated by Claude Code (Opus 5.5).
 * The AI-generated portions may be considered public domain (CC0-1.0)
 * and not subject to the project's licence. The human contributor has
 * reviewed and verified that the code is correct.
 *
 * SPDX-License-Identifier: MIT and CC0-1.0
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** ThreadX Test                                                          */
/**                                                                       */
/**   Module execution harness: the test module                           */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

/* One module, built twice: once user mode with memory protection and once
   privileged without it, from the same source; only the preamble's property
   word differs.

   The start thread exercises the kernel through the module's dispatcher: it
   allocates and creates a queue, a semaphore and a worker thread, hands the
   worker a message, waits for the worker to signal back, sleeps on the timer,
   and records what it saw in the area the manager shared with it.  Then, if
   the manager supplied the address of a word in kernel memory, it reads that
   word.  A protected module must fault on the read and never record its
   result; a privileged one reads it.  The done word is written last, so a
   module that faults never sets it.

   MISRA C:2023 deviations, confined to this test module: Rule 1.2 and
   Directive 4.3 (inline assembly to read CONTROL), and Rule 11.4 (the shared
   area and the kernel word are integer addresses supplied at run time).  */

#define TXM_MODULE
#include "txm_module.h"
#include "module_shared.h"

#define WORKER_STACK_SIZE   ((ULONG) 1024UL)
#define SLEEP_TICKS         ((ULONG) 5UL)
#define WAIT_TICKS          ((ULONG) 100UL)

static TX_THREAD    *worker_thread;
static TX_QUEUE     *message_queue;
static TX_SEMAPHORE *done_semaphore;
static ULONG        worker_stack[WORKER_STACK_SIZE / sizeof(ULONG)];
static ULONG        queue_storage[4];

VOID    module_start(ULONG id);


/* Keep the first failing status rather than the last.  */
static VOID  record_status(ULONG word, UINT status)
{
    if ((MODULE_SHARED[word] == (ULONG) TX_SUCCESS) && (status != TX_SUCCESS))
    {
        MODULE_SHARED[word] = (ULONG) status;
    }
}


static VOID  worker_entry(ULONG thread_input)
{
ULONG   message;

    (VOID) thread_input;

    for (;;)
    {
        message = 0UL;
        if (tx_queue_receive(message_queue, &message, TX_WAIT_FOREVER) == TX_SUCCESS)
        {
            MODULE_SHARED[MODULE_OUT_QUEUE_VALUE] = message;
            MODULE_SHARED[MODULE_OUT_WORKER_RUNS] = MODULE_SHARED[MODULE_OUT_WORKER_RUNS] + 1UL;
            (VOID) tx_semaphore_put(done_semaphore);
        }
    }
}


VOID  module_start(ULONG id)
{
ULONG   message;
ULONG   start_time;
ULONG   control;
ULONG   kernel_word;

    (VOID) id;

    MODULE_SHARED[MODULE_OUT_STARTED] =   MODULE_STARTED_MAGIC;
    MODULE_SHARED[MODULE_OUT_CYCLE_SEEN] = MODULE_SHARED[MODULE_IN_CYCLE];

    __asm__ volatile ("mrs %0, control" : "=r"(control));
    MODULE_SHARED[MODULE_OUT_CONTROL] = control;

    record_status(MODULE_OUT_OBJECT_STATUS, txm_module_object_allocate((VOID **) &message_queue, sizeof(TX_QUEUE)));
    record_status(MODULE_OUT_OBJECT_STATUS, txm_module_object_allocate((VOID **) &done_semaphore, sizeof(TX_SEMAPHORE)));
    record_status(MODULE_OUT_OBJECT_STATUS, txm_module_object_allocate((VOID **) &worker_thread, sizeof(TX_THREAD)));

    record_status(MODULE_OUT_CREATE_STATUS, tx_queue_create(message_queue, "module queue", TX_1_ULONG,
                                                            queue_storage, sizeof(queue_storage)));
    record_status(MODULE_OUT_CREATE_STATUS, tx_semaphore_create(done_semaphore, "module semaphore", 0UL));
    record_status(MODULE_OUT_CREATE_STATUS, tx_thread_create(worker_thread, "module worker", worker_entry, 0UL,
                                                             worker_stack, sizeof(worker_stack),
                                                             2U, 2U, TX_NO_TIME_SLICE, TX_AUTO_START));

    message = MODULE_QUEUE_MESSAGE;
    record_status(MODULE_OUT_CREATE_STATUS, tx_queue_send(message_queue, &message, TX_NO_WAIT));
    MODULE_SHARED[MODULE_OUT_SEMAPHORE_STATUS] = (ULONG) tx_semaphore_get(done_semaphore, WAIT_TICKS);

    start_time = tx_time_get();
    (VOID) tx_thread_sleep(SLEEP_TICKS);
    MODULE_SHARED[MODULE_OUT_SLEEP_TICKS] = tx_time_get() - start_time;

    kernel_word = MODULE_SHARED[MODULE_IN_KERNEL_WORD];
    if (kernel_word != 0UL)
    {
        MODULE_SHARED[MODULE_OUT_KERNEL_READ_TRY] =  1UL;
        MODULE_SHARED[MODULE_OUT_KERNEL_VALUE] =     *((volatile ULONG *) kernel_word);
        MODULE_SHARED[MODULE_OUT_KERNEL_READ_DONE] = 1UL;
    }

    MODULE_SHARED[MODULE_DONE] = MODULE_DONE_MAGIC;
}