OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [test_suite0/] [src/] [api/] [ipc.c] - Blame information for rev 5

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Test ipc system call.
3
 *
4
 * Copyright (C) 2010 B Labs Ltd.
5
 *
6
 * Author: Bahadir Balban
7
 */
8
#include <l4lib/macros.h>
9
#include L4LIB_INC_ARCH(syslib.h)
10
#include L4LIB_INC_ARCH(syscalls.h)
11
#include <l4lib/lib/thread.h>
12
#include <l4lib/ipcdefs.h>
13
#include <tests.h>
14
#include <macros.h>
15
#include <fault.h>
16
#include <memory.h>
17
 
18
struct ipc_ext_data {
19
        void *virtual;  /* Virtual address to start ipc from */
20
        l4id_t partner; /* Partner to do extended ipc */
21
};
22
 
23
int ipc_extended_sender(void *arg)
24
{
25
        struct ipc_ext_data *data = arg;
26
        int err;
27
 
28
        if ((err = l4_send_extended(data->partner, 0,
29
                                    SZ_2K, data->virtual)) < 0) {
30
                printf("%s: Extended send failed. err=%d\n",
31
                       __FUNCTION__, err);
32
        }
33
        return 0;
34
}
35
 
36
int ipc_extended_receiver(void *arg)
37
{
38
        struct ipc_ext_data *data = arg;
39
        int err;
40
 
41
        if ((err = l4_receive_extended(data->partner, SZ_2K,
42
                                       data->virtual)) < 0) {
43
                printf("%s: Extended receive failed. err=%d\n",
44
                       __FUNCTION__, err);
45
        }
46
 
47
        /*
48
         * Test the data received
49
         */
50
        for (int i = 0; i < SZ_2K; i++) {
51
                if (((char *)data->virtual)[i] != 'A' + i)
52
                        printf("%s: Extended receive buffer has unexpected "
53
                               "data: Start %p, Offset: %d, "
54
                               "Data=%d, expected=%d\n", __FUNCTION__,
55
                               data->virtual, i, ((char *)data->virtual)[i],
56
                               'A' + i);
57
                return err;
58
        }
59
 
60
        return 0;
61
}
62
 
63
int ipc_ext_handle_pfault(struct ipc_ext_data *ipc_data,
64
                          void **virt, void **phys)
65
{
66
        u32 mr[MR_UNUSED_TOTAL];
67
        struct fault_data fault;
68
        int err;
69
 
70
        /* Read mrs not used by syslib */
71
        for (int i = 0; i < MR_UNUSED_TOTAL; i++)
72
                mr[i] = read_mr(MR_UNUSED_START + i);
73
 
74
        fault.kdata = (fault_kdata_t *)&mr[0];
75
        fault.sender = l4_get_sender();
76
 
77
        /* Convert from arch-specific to generic fault data */
78
        set_generic_fault_params(&fault);
79
 
80
        /*
81
         * Handle the fault using a basic logic - if a virtual index
82
         * is faulted, map the corresponding page at same physical index.
83
         */
84
        if (page_align(fault.address) == (unsigned long)virt[0]) {
85
                if ((err = l4_map(phys[0], virt[0], 1,
86
                                  MAP_USR_RW, fault.sender)) < 0) {
87
                        printf("%s: Error: l4_map failed. "
88
                               "phys=%p, virt=%p\n", __FUNCTION__,
89
                               phys[0], virt[0]);
90
                        return err;
91
                }
92
        } else if (page_align(fault.address) == (unsigned long)virt[1]) {
93
                if ((err = l4_map(phys[1], virt[1], 1,
94
                                  MAP_USR_RW, fault.sender)) < 0) {
95
                        printf("%s: Error: l4_map failed. "
96
                               "phys=%p, virt=%p\n", __FUNCTION__,
97
                               phys[1], virt[1]);
98
                        return err;
99
                }
100
        } else if (page_align(fault.address) == (unsigned long)virt[2]) {
101
                if ((err = l4_map(phys[2], virt[2], 1,
102
                                  MAP_USR_RW, fault.sender)) < 0) {
103
                        printf("%s: Error: l4_map failed. "
104
                               "phys=%p, virt=%p\n", __FUNCTION__,
105
                               phys[2], virt[2]);
106
                        return err;
107
                }
108
        } else if (page_align(fault.address) == (unsigned long)virt[3]) {
109
                if ((err = l4_map(phys[3], virt[3], 1,
110
                                  MAP_USR_RW, fault.sender)) < 0) {
111
                        printf("%s: Error: l4_map failed. "
112
                               "phys=%p, virt=%p\n", __FUNCTION__,
113
                               phys[3], virt[3]);
114
                        return err;
115
                }
116
        } else {
117
                printf("%s: Error, page fault occured on an unexpected "
118
                       "address. adress=0x%x\n", __FUNCTION__,
119
                       fault.address);
120
                return -1;
121
        }
122
 
123
        /* Reply back to fault thread and return */
124
        return l4_ipc_return(0);
125
}
126
 
127
/*
128
 * Create two threads who will do page-faulting ipc to each other.
129
 * Their parent waits and handles the page faults.
130
 *
131
 * This test allocates 4 virtual page and 4 physical page addresses.
132
 * It fills a total of 2KB of payload starting from the 3rd quarter
133
 * of the first page and until the 2nd quarter of the 2nd page to
134
 * be sent by the sender thread.
135
 *
136
 * The payload is copied and the pages deliberately unmapped so that
137
 * the sender thread will page fault during the send operation.
138
 *
139
 * The receive pages are also set up same as above, so the receiving
140
 * thread also faults during the receive.
141
 *
142
 * The main thread starts both ipc threads, and starts waiting on
143
 * page faults. It handles the faults and the test succeeds if the
144
 * data is transfered safely to receiving end, despite all faults.
145
 */
146
int test_ipc_extended(void)
147
{
148
        struct task_ids self_ids;
149
        struct ipc_ext_data ipc_data[2];
150
        struct l4_thread *thread[2];
151
        void *virt[4], *phys[4];
152
        int err, tag;
153
 
154
        l4_getid(&self_ids);
155
 
156
        /* Get 4 physical pages */
157
        for (int i = 0; i < 4; i++)
158
                phys[i] = physical_page_new(1);
159
 
160
        /* Get 2 pairs of virtual pages */
161
        virt[0] = virtual_page_new(2);
162
        virt[1] = virt[0] + PAGE_SIZE;
163
        virt[2] = virtual_page_new(2);
164
        virt[3] = virt[2] + PAGE_SIZE;
165
 
166
        /* Map sender pages to self */
167
        if ((err = l4_map(phys[0], virt[0], 1,
168
                          MAP_USR_RW, self_ids.tid)) < 0) {
169
                printf("Error: Mapping Sender pages failed. phys: 0x%p,"
170
                       " virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0],
171
                       self_ids.tid, err);
172
                return err;
173
        }
174
        if ((err = l4_map(phys[1], virt[1], 1,
175
                          MAP_USR_RW, self_ids.tid)) < 0) {
176
                printf("Error: Mapping Sender pages failed. phys: 0x%p,"
177
                       " virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0],
178
                       self_ids.tid, err);
179
                return err;
180
        }
181
 
182
        /*
183
         * Fill them with values to be sent
184
         * Filling in 3rd KB of first page to 2nd KB of second page
185
         */
186
        for (int i = 0; i < SZ_2K; i++)
187
                ((char *)virt[0] + SZ_1K * 3)[i] = 'A' + i;
188
 
189
        /* Unmap the pages */
190
        l4_unmap(virt[0], 2, self_ids.tid);
191
 
192
        /* Create ipc threads but don't start. */
193
        if ((err = thread_create(ipc_extended_sender,
194
                                 &ipc_data[0],
195
                                 TC_SHARE_SPACE | TC_NOSTART,
196
                                 &thread[0])) < 0) {
197
                dbg_printf("Thread create failed. "
198
                           "err=%d\n", err);
199
                return err;
200
        }
201
 
202
        dbg_printf("Thread created successfully. "
203
                   "tid=%d\n", thread[0]->ids.tid);
204
 
205
        if ((err = thread_create(ipc_extended_receiver,
206
                                 &ipc_data[1],
207
                                 TC_SHARE_SPACE | TC_NOSTART,
208
                                 &thread[1])) < 0) {
209
                dbg_printf("Thread create failed. "
210
                           "err=%d\n", err);
211
                return err;
212
        }
213
 
214
        dbg_printf("Thread created successfully. "
215
                   "tid=%d\n", thread[1]->ids.tid);
216
 
217
        /*
218
         * Set up arguments to sender,
219
         * Send offset at 3rd quarter of first page.
220
         */
221
        ipc_data[0].virtual = virt[0] + SZ_1K * 3;
222
        ipc_data[0].partner = thread[1]->ids.tid;
223
 
224
        /*
225
         * Set up arguments to receiver
226
         * Receive offset at 3rd quarter of first page.
227
         */
228
        ipc_data[1].virtual = virt[1] + SZ_1K * 3;
229
        ipc_data[1].partner = thread[0]->ids.tid;
230
 
231
        /* Start the threads */
232
        l4_thread_control(THREAD_RUN, &thread[0]->ids);
233
        l4_thread_control(THREAD_RUN, &thread[1]->ids);
234
 
235
        /* Expecting 4 faults on 4 pages */
236
        for (int i = 0; i < 4; i++) {
237
                /* Wait on page fault */
238
                if ((err = l4_receive(L4_ANYTHREAD)) < 0) {
239
                        printf("Error: l4_receive() for page"
240
                               " fault has failed. err=%d\n",
241
                               err);
242
                }
243
                if ((tag = l4_get_tag()) != L4_IPC_TAG_PFAULT) {
244
                        printf("Error: Parent thread received "
245
                               "non-page fault ipc tag. tag=%d\n",
246
                               tag);
247
                        return -1;
248
                }
249
 
250
                /* Handle fault */
251
                if ((err = ipc_ext_handle_pfault(ipc_data, virt, phys)) < 0) {
252
                        printf("Error: An error occured during ipc "
253
                               "page fault handling. err=%d\n", err);
254
                        return err;
255
                }
256
        }
257
 
258
        /* Wait for the ipc threads */
259
        for (int i = 0; i < 2; i ++)
260
                if ((err = thread_wait(thread[i])) < 0) {
261
                        dbg_printf("THREAD_WAIT failed. "
262
                                   "err=%d\n", err);
263
                        return err;
264
                }
265
 
266
        /* Unmap and release pages */
267
        for (int i = 0; i < 4; i++) {
268
                l4_unmap(virt[i], 1, self_ids.tid);
269
                virtual_page_free(virt[i], 1);
270
                physical_page_free(phys[i], 1);
271
        }
272
 
273
        return 0;
274
}
275
 
276
int ipc_full_thread(void *arg)
277
{
278
        l4id_t parent = *((l4id_t *)arg);
279
        int err;
280
 
281
        /* Do two full send/receives */
282
        for (int i = 0; i < 2; i++) {
283
                /* Full receive, return positive if error */
284
                if ((err = l4_receive_full(parent)) < 0) {
285
                        dbg_printf("Full receive failed on new "
286
                                   "thread. err=%d", err);
287
                        return 1;
288
                }
289
 
290
                /* Test full utcb received values */
291
                for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
292
                        if (read_mr(i) != i) {
293
                                dbg_printf("IPC full receive on new thread: "
294
                                           "Unexpected message register "
295
                                           "values. MR%d = %d, should be %d\n",
296
                                           i, read_mr(i), i);
297
                                return 1; /* Exit positive without reply */
298
                        }
299
                }
300
 
301
                /*
302
                 * Reset all message registers
303
                 */
304
                for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
305
                        write_mr(i, 0);
306
 
307
                /* Send full return reply */
308
                l4_send_full(parent, 0);
309
        }
310
        return 0;
311
}
312
 
313
int ipc_short_thread(void *arg)
314
{
315
        l4id_t parent = *((l4id_t *)arg);
316
        int err;
317
 
318
        /* Short receive, return positive if error */
319
        if ((err = l4_receive(parent)) < 0) {
320
                dbg_printf("Short receive failed on new "
321
                           "thread. err=%d", err);
322
                return 1;
323
        }
324
 
325
        /* Test received registers */
326
        for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) {
327
                if (read_mr(i) != i) {
328
                        dbg_printf("IPC Receive on new thread: "
329
                                   "Unexpected message register "
330
                                   "values.\n"
331
                                   "read = %d, expected = %d\n",
332
                                   read_mr(i), i);
333
                        l4_print_mrs();
334
                        return 1; /* Exit positive without reply */
335
                }
336
        }
337
 
338
        /*
339
         * Reset all message registers
340
         */
341
        for (int i = MR_UNUSED_START; i < MR_TOTAL; i++)
342
                write_mr(i, 0);
343
 
344
        /*
345
         * Send return reply and exit
346
         */
347
        return l4_send(parent, 0);
348
}
349
 
350
 
351
/*
352
 * Create a thread and do a full ipc to it
353
 */
354
int test_ipc_full(void)
355
{
356
        struct task_ids self_ids;
357
        struct l4_thread *thread;
358
        int err;
359
 
360
        l4_getid(&self_ids);
361
 
362
        /*
363
         * Create a thread in the same space
364
         */
365
        if ((err = thread_create(ipc_full_thread,
366
                                 &self_ids.tid,
367
                                 TC_SHARE_SPACE,
368
                                 &thread)) < 0) {
369
                dbg_printf("Thread create failed. "
370
                           "err=%d\n", err);
371
                return err;
372
        }
373
 
374
        dbg_printf("Thread created successfully. "
375
                   "tid=%d\n", thread->ids.tid);
376
 
377
        /*
378
         * Try one short and one full send/recv
379
         * to test full send/recv occurs on both cases
380
         */
381
 
382
        /*
383
         * Write data to full utcb registers
384
         */
385
        for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
386
                write_mr(i, i);
387
 
388
        /*
389
         * First, do a full ipc send/recv
390
         */
391
        if ((err = l4_sendrecv_full(thread->ids.tid,
392
                                    thread->ids.tid,
393
                                    0)) < 0) {
394
                dbg_printf("Full IPC send/recv failed. "
395
                           "err=%d\n", err);
396
                return err;
397
        }
398
 
399
        /*
400
         * Check that payload registers are modified to 0
401
         */
402
        dbg_printf("%s: After send/recv:\n", __FUNCTION__);
403
        for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
404
                if (read_mr(i) != 0) {
405
                        dbg_printf("Full IPC send/recv: "
406
                                   "Received payload is not "
407
                                   "as expected.\n "
408
                                   "MR%d = %d, should be %d\n",
409
                                   i, read_mr(i), 0);
410
                        return -1;
411
                }
412
        }
413
 
414
        /*
415
         * Write data to full utcb registers
416
         */
417
        for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
418
                write_mr(i, i);
419
 
420
        /*
421
         * Try a short ipc send/recv. This should still result
422
         * in full ipc since the other side is doing full send/recv.
423
         */
424
        if ((err = l4_sendrecv(thread->ids.tid,
425
                               thread->ids.tid,
426
                               0)) < 0) {
427
                dbg_printf("Full IPC send/recv failed. "
428
                           "err=%d\n", err);
429
                return err;
430
        }
431
 
432
        /*
433
         * Check that payload registers are modified to 0
434
         */
435
        // dbg_printf("%s: After send/recv:\n", __FUNCTION__);
436
        for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
437
                // dbg_printf("MR%d: %d\n", i, read_mr(i));
438
                if (read_mr(i) != 0) {
439
                        dbg_printf("Full IPC send/recv: "
440
                                   "Received payload is not "
441
                                   "as expected.\n "
442
                                   "MR%d = %d, should be %d\n",
443
                                   i, read_mr(i), 0);
444
                        return -1;
445
                }
446
        }
447
 
448
        /* Wait for the ipc thread to die */
449
        if ((err = thread_wait(thread)) < 0) {
450
                dbg_printf("THREAD_WAIT failed. "
451
                           "err=%d\n", err);
452
                return err;
453
        }
454
 
455
        dbg_printf("Full IPC send/recv successful.\n");
456
        return 0;
457
}
458
 
459
/*
460
 * Create a thread and do a short ipc to it
461
 */
462
int test_ipc_short(void)
463
{
464
        struct task_ids self_ids;
465
        struct l4_thread *thread;
466
        int err;
467
 
468
        l4_getid(&self_ids);
469
 
470
        /*
471
         * Create a thread in the same space
472
         */
473
        if ((err = thread_create(ipc_short_thread,
474
                                 &self_ids.tid,
475
                                 TC_SHARE_SPACE,
476
                                 &thread)) < 0) {
477
                dbg_printf("Thread create failed. "
478
                           "err=%d\n", err);
479
                return err;
480
        }
481
 
482
        dbg_printf("Thread created successfully. "
483
                   "tid=%d\n", thread->ids.tid);
484
 
485
        /*
486
         * Write data to short ipc registers
487
         */
488
        for (int i = MR_UNUSED_START; i < MR_TOTAL; i++)
489
                write_mr(i, i);
490
 
491
        /*
492
         * Do short ipc send/recv and check data is reset
493
         */
494
        if ((err = l4_sendrecv(thread->ids.tid,
495
                               thread->ids.tid,
496
                               0)) < 0) {
497
                dbg_printf("Short IPC send/recv failed. "
498
                           "err=%d\n", err);
499
                return err;
500
        }
501
 
502
        /*
503
         * Check that payload registers are reset
504
         */
505
        for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) {
506
                if (read_mr(i) != 0) {
507
                        dbg_printf("Short IPC send/recv: "
508
                                   "Received payload is incorrect."
509
                                   "read = %d, expected=%d\n",
510
                                   read_mr(i), 0);
511
                        return -1;
512
                }
513
        }
514
 
515
        /* Wait for the ipc thread */
516
        if ((err = thread_wait(thread)) < 0) {
517
                dbg_printf("THREAD_WAIT failed. "
518
                           "err=%d\n", err);
519
                return err;
520
        }
521
 
522
        dbg_printf("Short IPC send/recv successful.\n");
523
        return 0;
524
}
525
 
526
int test_api_ipc(void)
527
{
528
        int err;
529
 
530
        if ((err = test_ipc_extended()) < 0)
531
                goto out_err;
532
 
533
        if ((err = test_ipc_short()) < 0)
534
                goto out_err;
535
 
536
        if ((err = test_ipc_full()) < 0)
537
                goto out_err;
538
 
539
        printf("IPC:                           -- PASSED --\n");
540
        return 0;
541
 
542
out_err:
543
        printf("IPC:                           -- FAILED --\n");
544
        return err;
545
 
546
}
547
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.