1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/*- import 'helpers/error.c' as error with context -*/
14
15#include <camkes/error.h>
16#include <camkes/tls.h>
17#include <limits.h>
18#include <sel4/sel4.h>
19#include <stdbool.h>
20#include <stdlib.h>
21#include <sync/bin_sem_bare.h>
22#include <sync/sem-bare.h>
23#include <utils/util.h>
24
25/*? macros.show_includes(me.instance.type.includes) ?*/
26
27/* Interface-specific error handling. */
28/*- set error_handler = '%s_error_handler' % me.interface.name -*/
29/*? error.make_error_handler(me.interface.name, error_handler) ?*/
30
31/*- set id = me.parent.to_ends.index(me) -*/
32
33/*- set ep = alloc('ep_%d' % id, seL4_EndpointObject, read=True) -*/
34/*- set handoff = alloc('handoff_%d' % id, seL4_EndpointObject, label=me.instance.name, read=True, write=True) -*/
35static volatile int handoff_value;
36
37char to_/*? id ?*/_/*? me.interface.name ?*/_data[ROUND_UP_UNSAFE(sizeof(int), PAGE_SIZE_4K)]
38   ALIGN(4096)
39   SECTION("align_12bit");
40static volatile int *value = (volatile int*)to_/*? id ?*/_/*? me.interface.name ?*/_data;
41/*? register_shared_variable('%s_%d_data' % (me.parent.name, id), 'to_%d_%s_data' % (id, me.interface.name), 4096, perm='RW') ?*/
42
43/*- set lock = alloc('lock_%d' % id, seL4_NotificationObject, label=me.instance.name, read=True, write=True) -*/
44static volatile int lock_count = 1;
45
46static int lock(void) {
47    int result = sync_bin_sem_bare_wait(/*? lock ?*/, &lock_count);
48    __sync_synchronize();
49    return result;
50}
51
52static int unlock(void) {
53    __sync_synchronize();
54    return sync_bin_sem_bare_post(/*? lock ?*/, &lock_count);
55}
56
57static void (*volatile callback)(void*);
58static void *callback_arg;
59
60int /*? me.interface.name ?*/__run(void) {
61    while (true) {
62restart:;
63        int result UNUSED = sync_sem_bare_wait(/*? ep ?*/, value);
64        ERR_IF(result != 0, /*? error_handler ?*/, ((camkes_error_t){
65                .type = CE_OVERFLOW,
66                .instance = "/*? me.instance.name ?*/",
67                .interface = "/*? me.interface.name ?*/",
68                .description = "waiting on semaphore failed",
69            }), ({
70                goto restart;
71            }));
72
73        if (lock() != 0) {
74            ERR(/*? error_handler ?*/, ((camkes_error_t){
75                    .type = CE_OVERFLOW,
76                    .instance = "/*? me.instance.name ?*/",
77                    .interface = "/*? me.interface.name ?*/",
78                    .description = "lock acquisition failed due to too many outstanding lock holders",
79                }), ({
80                    goto restart;
81                }));
82        }
83
84        void (*cb)(void*) = callback;
85        callback = NULL;
86        void *arg = callback_arg;
87
88        if (cb == NULL) {
89            ERR_IF(handoff_value == INT_MAX, /*? error_handler ?*/, ((camkes_error_t){
90                    .type = CE_OVERFLOW,
91                    .instance = "/*? me.instance.name ?*/",
92                    .interface = "/*? me.interface.name ?*/",
93                    .description = "handoff to internal endpoint not possible due to counter overflow",
94                }), ({
95                    int result UNUSED = unlock();
96                    assert(result == 0);
97                    goto restart;
98                }));
99            sync_sem_bare_post(/*? handoff ?*/, &handoff_value);
100        }
101
102        result = unlock();
103        assert(result == 0);
104
105        if (cb != NULL) {
106            cb(arg);
107        }
108    }
109}
110
111static int poll(void) {
112    return sync_sem_bare_trywait(/*? handoff ?*/, &handoff_value) == 0;
113}
114
115int /*? me.interface.name ?*/_poll(void) {
116    return poll();
117}
118
119void /*? me.interface.name ?*/_wait(void) {
120#ifndef CONFIG_KERNEL_MCS
121    camkes_protect_reply_cap();
122#endif
123    if (sync_sem_bare_wait(/*? handoff ?*/, &handoff_value) != 0) {
124        ERR(/*? error_handler ?*/, ((camkes_error_t){
125                .type = CE_OVERFLOW,
126                .instance = "/*? me.instance.name ?*/",
127                .interface = "/*? me.interface.name ?*/",
128                .description = "wait failed due to future counter overflow",
129            }), ({
130                return;
131            }));
132    }
133}
134
135int /*? me.interface.name ?*/_reg_callback(void (*cb)(void*), void *arg) {
136
137    if (poll()) {
138        cb(arg);
139        return 0;
140    }
141
142    if (lock() != 0) {
143        return -1;
144    }
145
146    if (poll()) {
147        int result UNUSED = unlock();
148        assert(result == 0);
149        cb(arg);
150        return 0;
151
152    } else if (callback != NULL) {
153        int result UNUSED = unlock();
154        assert(result == 0);
155        return -1;
156
157    } else {
158        callback = cb;
159        callback_arg = arg;
160        int result UNUSED = unlock();
161        assert(result == 0);
162        return 0;
163    }
164}
165