aboutsummaryrefslogtreecommitdiff
path: root/arm/tztest_secure_svc.c
blob: 6722f3e5e098f9e587eced2de88c0736ad925678 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include "tztest.h"

/* Make the below globals volatile as  found that the compiler uses the
 * register value ratherh than the memory value making it look like the writes
 * actually happened.
 */
extern int _ram_nsec_base;

int dispatch_secure_usr(int, int);
void tztest_secure_svc_loop(int initial_r0, int initial_r1);
void *sec_allocate_secure_memory(int);
extern uint32_t _sec_l1_page_table;
uint32_t *sec_l1_page_table = &_sec_l1_page_table;
extern uint32_t _ram_sectext_start;
extern uint32_t _ram_secdata_start;
extern uint32_t _secstack_start;
extern uint32_t _sectext_size;
extern uint32_t _secdata_size;
extern uint32_t _secstack_size;
extern uint32_t _shared_memory_heap_base;
extern uint32_t _common_memory_heap_base;
extern volatile int _tztest_exception;
extern volatile int _tztest_exception_addr;
extern volatile int _tztest_exception_status;
extern volatile int _tztest_test_count;
extern volatile int _tztest_fail_count;
volatile int *tztest_test_count = &_tztest_test_count;
volatile int *tztest_fail_count = &_tztest_fail_count;
volatile int *tztest_exception = &_tztest_exception;
volatile int *tztest_exception_addr = &_tztest_exception_addr;
volatile int *tztest_exception_status = &_tztest_exception_status;
uint32_t ram_sectext_start = (uint32_t)&_ram_sectext_start;
uint32_t ram_secdata_start = (uint32_t)&_ram_secdata_start;
uint32_t secstack_start = (uint32_t)&_secstack_start;
uint32_t sectext_size = (uint32_t)&_sectext_size;
uint32_t secdata_size = (uint32_t)&_secdata_size;
uint32_t secstack_size = (uint32_t)&_secstack_size;

pagetable_map_entry_t nsec_pagetable_entries[] = {
    {.va = (uint32_t)&_ram_nsec_base, .pa = (uint32_t)&_ram_nsec_base,
     .type = SECTION, .len = SECTION_SIZE * 2,
     .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P1_X | P0_R |
             P0_W | P0_X | NONSECURE },
};

pagetable_map_entry_t sysreg_pagetable_entries[] = {
    {.va = SYSREG_BASE, .pa = SYSREG_BASE,
     .type = PAGE, .len = 0x1000,
     .attr = SHARED | NOTGLOBAL | UNCACHED | P1_R | P1_W | P0_R | P0_W |
             NONSECURE },
};

void sec_svc_handler(volatile uint32_t op, volatile tztest_svc_desc_t *desc)
{
    DEBUG_MSG("Entered\n");
    switch (op) {
        case SVC_DISPATCH_MONITOR:
            op = SMC_DISPATCH_MONITOR;
            __smc(op, desc);
            break;
        case SVC_GET_SECURE_STATE:
            /* This SVC handler is only accessible from the secure vector
             * table, so unless something went drastically wrong with the
             * tables, it should be safe to assume we are in a nonsecure state.
             */
            desc->secure_state.state = TZTEST_STATE_SECURE;
            break;
    }
    DEBUG_MSG("Exiting\n");
    return;
}

void sec_undef_handler() {
    DEBUG_MSG("Undefined exception taken\n");
    *tztest_exception = CPSR_MODE_UND;
    *tztest_exception_status = 0;
}

void sec_pabort_handler(int status, int addr) {
    DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", status, addr);
    *tztest_exception = CPSR_MODE_ABT;
    *tztest_exception_addr = addr;
    *tztest_exception_status = status & 0x1f;
}

void sec_dabort_handler(int status, int addr) {
    DEBUG_MSG("Data Abort: %s\n", FAULT_STR(status & 0x1f));
    DEBUG_MSG("status = 0x%x\taddress = 0x%x\n",
              status & 0x1f, addr);
    *tztest_exception = CPSR_MODE_ABT;
    *tztest_exception_addr = addr;
    *tztest_exception_status = status & 0x1f;
}

void check_init_mode()
{
    printf("\nValidating startup state:\n");

    printf("\tChecking for security extension ...");
    int idpfr1 = 0;
    /* Read the ID_PFR1 CP register and check that it is marked for support of
     * the security extension.
     */
    __mrc(15, 0, idpfr1, 0, 1, 1);
    if (0x10 != (idpfr1 & 0xf0)) {
        printf("FAILED\n");
        DEBUG_MSG("current IDPFR1 (%d) != expected IDPFR1 (%d)\n",
                  (idpfr1 & 0xf0), 0x10);
        assert(0x10 == (idpfr1 & 0xf0));
    } else {
        printf("PASSED\n");
    }

    printf("\tChecking initial processor mode... ");
    if (CPSR_MODE_SVC != (_read_cpsr() & 0x1f)) {
        printf("FAILED\n");
        DEBUG_MSG("current CPSR (%d) != expected CPSR (%d)\n",
                  (_read_cpsr() & 0x1f), CPSR_MODE_SVC);
        assert(CPSR_MODE_SVC == (_read_cpsr() & 0x1f));
    } else {
        printf("PASSED\n");
    }

    // Test: Check that on reset if sec et present, starts in sec state
    //      pg. B1-1204
    printf("\tChecking initial security state... ");
    if (0 != (_read_scr() & SCR_NS)) {
        printf("Failed\n");
        DEBUG_MSG("current SCR.NS (%d) != expected SCR.NS (%d)\n",
                  (_read_cpsr() & SCR_NS), 0);
        assert(0 == (_read_scr() & SCR_NS));
    } else {
        printf("PASSED\n");
    }
}

void tztest_secure_svc_loop(int initial_op, int initial_data)
{
    volatile int op = initial_op;
    tztest_smc_desc_t *data = (tztest_smc_desc_t *)initial_data;
    uint32_t (*func)(uint32_t);

    DEBUG_MSG("Initial call\n");

    while (SMC_EXIT != op) {
        switch (op) {
            case SMC_DISPATCH_SECURE_USR:
                DEBUG_MSG("Dispatching secure USR function\n");
                data->dispatch.ret =
                    dispatch_secure_usr((int)data->dispatch.func,
                                        data->dispatch.arg);
                DEBUG_MSG("Returned from secure USR dispatch\n");
                break;
            case SMC_DISPATCH_SECURE_SVC:
                func = (uint32_t (*)())data->dispatch.func;
                DEBUG_MSG("Dispatching secure SVC function\n");
                data->dispatch.ret = func(data->dispatch.arg);
                DEBUG_MSG("Returned from secure SVC dispatch\n");
                break;
        }
        __smc(op, data);
        DEBUG_MSG("Handling smc op 0x%x\n", op);
    }

    DEBUG_MSG("Exiting\n");
}

void tztest_secure_pagetable_init()
{
    pagetable_map_entry_t sec_pagetable_entries[] = {
        {.va = (uint32_t)ram_sectext_start, .pa = (uint32_t)ram_sectext_start,
         .type = PAGE, .len = sectext_size,
         .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_X | P0_R | P0_X },
        {.va = (uint32_t)ram_secdata_start, .pa = (uint32_t)ram_secdata_start,
         .type = PAGE, .len = secdata_size,
         .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W },
        {.va = (uint32_t)secstack_start, .pa = (uint32_t)secstack_start,
         .type = PAGE, .len = secstack_size,
         .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W },
    };

    pagetable_init(sec_l1_page_table);

    PT_ADD_ENTRIES(sec_l1_page_table, sysreg_pagetable_entries);
    PT_ADD_ENTRIES(sec_l1_page_table, sec_pagetable_entries);
    PT_ADD_ENTRIES(sec_l1_page_table, nsec_pagetable_entries);

    pagetable_init_common(sec_l1_page_table);
}

void tztest_secure_svc_init_monitor(uint32_t entry_point)
{
    struct sm_nsec_ctx *nsec_ctx;


    /* Set-up the non-secure context so that the switch to nonsecure state
     * resumes at initiallizing the nonsecure svc mode.
     */
    nsec_ctx = sm_get_nsec_ctx();
    nsec_ctx->mon_lr = entry_point;
    nsec_ctx->mon_spsr = CPSR_MODE_SVC | CPSR_I;
}

void tztest_dispatch_monitor(tztest_smc_desc_t *desc)
{
    uint32_t (*func)(uint32_t) = desc->dispatch.func;
    DEBUG_MSG("Entered\n");
    desc->dispatch.ret = func(desc->dispatch.arg);
    DEBUG_MSG("Exiting\n");
}