summaryrefslogtreecommitdiff
path: root/test/tx/cmake/module_qemu/tests/test_module_fault.c
blob: 36bcdc9a6ab1ccd21b7de147e1a6ff4f4a3499b5 (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
/***************************************************************************
 * 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: protected module memory fault             */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

/* A user-mode, memory-protected module that reads a word of kernel memory must
   take a MemManage fault on that read.  The Module Manager must terminate the
   faulting thread, report it to the application's fault notification with the
   right module, thread and address, and still let the module be stopped and
   unloaded.

   This image is also the harness's proof that the emulated MPU is enforcing at
   all: if QEMU let the unprivileged read through, the module would record the
   value and finish, and every check below would fail.  */

#include "harness_checks.h"

#define MODULE_WAIT_TICKS       ((ULONG) 500UL)
#define PROTECTED_PROPERTIES    ((ULONG) 0x02000007UL)  /* GNU; user mode, memory protection, shared memory */
#define KERNEL_WORD_VALUE       ((ULONG) 0x6B65726EUL)

/* CFSR: MemManage data access violation, with MMFAR valid.  */
#define CFSR_DACCVIOL           ((ULONG) 0x02UL)
#define CFSR_MMARVALID          ((ULONG) 0x80UL)

extern UCHAR                    module_services_protected[];

static TXM_MODULE_INSTANCE      test_module;
static volatile ULONG           kernel_word = KERNEL_WORD_VALUE;


VOID  harness_test(VOID)
{
ULONG   available_before;
ULONG   start;

    harness_print("Module fault: protected module reads kernel memory\n");

    available_before = harness_module_pool_available();

    harness_shared_clear();
    MODULE_SHARED[MODULE_IN_CYCLE] =       1UL;
    MODULE_SHARED[MODULE_IN_KERNEL_WORD] = (ULONG) &kernel_word;

    harness_expect("memory load", (ULONG) txm_module_manager_memory_load(&test_module, "services protected",
                                                                         (VOID *) module_services_protected),
                   (ULONG) TX_SUCCESS);
    harness_expect("module properties", test_module.txm_module_instance_property_flags, PROTECTED_PROPERTIES);
    harness_expect("shared area grant", (ULONG) harness_shared_grant(&test_module), (ULONG) TX_SUCCESS);
    harness_expect("module start", (ULONG) txm_module_manager_start(&test_module), (ULONG) TX_SUCCESS);

    start = tx_time_get();
    while ((harness_fault_count == 0UL) && ((tx_time_get() - start) < MODULE_WAIT_TICKS))
    {
        tx_thread_sleep(1);
    }

    /* The kernel services before the read still worked.  */
    harness_check_services(1UL);
    harness_expect("module ran unprivileged", MODULE_SHARED[MODULE_OUT_CONTROL] & CONTROL_NPRIV, CONTROL_NPRIV);

    /* The read was attempted and faulted.  */
    harness_expect("kernel read attempted", MODULE_SHARED[MODULE_OUT_KERNEL_READ_TRY], 1UL);
    harness_expect("kernel read did not complete", MODULE_SHARED[MODULE_OUT_KERNEL_READ_DONE], 0UL);
    harness_expect("kernel value not disclosed", MODULE_SHARED[MODULE_OUT_KERNEL_VALUE], 0UL);
    harness_expect("module did not finish", MODULE_SHARED[MODULE_DONE], 0UL);

    harness_expect("one memory fault reported", harness_fault_count, 1UL);
    harness_expect("fault names the module", (ULONG) harness_fault_module, (ULONG) &test_module);
    harness_expect("fault names the start thread", (ULONG) harness_fault_thread,
                   (ULONG) &test_module.txm_module_instance_start_stop_thread);
    harness_expect("fault address is the kernel word", harness_fault_address, (ULONG) &kernel_word);
    harness_expect("fault is a data access violation",
                   harness_fault_status & (CFSR_DACCVIOL | CFSR_MMARVALID), CFSR_DACCVIOL | CFSR_MMARVALID);
    harness_expect("faulting thread terminated",
                   (ULONG) test_module.txm_module_instance_start_stop_thread.tx_thread_state, (ULONG) TX_TERMINATED);
    harness_expect("kernel word unchanged", kernel_word, KERNEL_WORD_VALUE);

    harness_expect("module stop", (ULONG) txm_module_manager_stop(&test_module), (ULONG) TX_SUCCESS);
    harness_expect("module unload", (ULONG) txm_module_manager_unload(&test_module), (ULONG) TX_SUCCESS);
    harness_expect("module memory returned", harness_module_pool_available(), available_before);
}