1/*
2 * Copyright 2016, 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(D61_BSD)
11 */
12
13#include <stdio.h>
14#include <assert.h>
15#include <refos/refos.h>
16#include <refos-util/init.h>
17#include <refos-io/morecore.h>
18#include "state.h"
19#include "dispatchers/dspace/dspace.h"
20#include "dispatchers/serv_dispatch.h"
21#include "dispatchers/client_watch.h"
22
23/*! @file
24    @brief Timer Server main source file.
25
26    The RefOS Timer server acts as the timer driver, and exposes a timer dataspace, which implements
27    gettime and sleep functionality.
28
29    @image html timeserv.png
30
31    The Timer server:
32    <ul>
33        <li>Does NOT support providing pager service to clients.</li>
34        <li>Does NOT support providing content-initialisation for another dataserver.</li>
35        <li>Does NOT supports parameter buffers using an external dataspace (i.e. a dataspace
36            provided by another dataserver).</li>
37        <li>Does NOT support parameter buffers using an internal dataspace (i.e. a dataspace
38            provided the fileserver itself).</li>
39        <li>Does NOT support having its dataspace content-initalised by an external dataspace.</li>
40        <li>Ignores nBytes parameter in open() method (timer dspace doesn't have a file size).</li>
41    </ul>
42
43    The timer server provides the dataspace `/dev_timer/timer`.
44    <ul>
45        <li>Writing a uint64_t to `/dev/timer` results a sleep() call for that many ns.</li>
46        <li>Reading a uint64_t from `/dev/timer` results in getting the current time in ns.</li>
47    </ul>
48*/
49
50/*! @brief timer server's static morecore region. */
51static char timeServMMapRegion[TIMESERV_MMAP_REGION_SIZE];
52
53/*! @brief Handle messages recieved by the timer server.
54    @param s The global timer server state. (No ownership transfer)
55    @param msg The recieved message. (No ownership transfer)
56    @return DISPATCH_SUCCESS if message dispatched, DISPATCH_ERROR if unknown message.
57*/
58static int
59timer_server_handle_message(struct timeserv_state *s, srv_msg_t *msg)
60{
61    int result = DISPATCH_PASS;
62    int label = seL4_GetMR(0);
63    void *userptr;
64
65    if (dispatch_client_watch(msg) == DISPATCH_SUCCESS) {
66        result = DISPATCH_SUCCESS;
67    }
68
69    if (dev_dispatch_interrupt(&timeServ.irqState, msg) == DISPATCH_SUCCESS) {
70        result = DISPATCH_SUCCESS;
71    }
72
73    if (result == DISPATCH_SUCCESS) {
74        return result;
75    }
76
77    if (check_dispatch_data(msg, &userptr) == DISPATCH_SUCCESS) {
78        result = rpc_sv_data_dispatcher(userptr, label);
79        assert(result == DISPATCH_SUCCESS);
80        return DISPATCH_SUCCESS;
81    }
82
83    if (check_dispatch_serv(msg, &userptr) == DISPATCH_SUCCESS) {
84        result = rpc_sv_serv_dispatcher(userptr, label);
85        assert(result == DISPATCH_SUCCESS);
86        return DISPATCH_SUCCESS;
87    }
88
89    dprintf("Unknown message (badge = %d msgInfo = %d label = %d).\n",
90            msg->badge, seL4_MessageInfo_get_label(msg->message), label);
91    ROS_ERROR("timer server unknown message.");
92    assert(!"timer server unknown message.");
93
94    return DISPATCH_ERROR;
95}
96
97/*! @brief Main timer server message loop. Simply loops through recieving and dispatching messages
98           repeatedly. */
99static void
100timer_server_mainloop(void)
101{
102    struct timeserv_state *s = &timeServ;
103    srv_msg_t msg;
104
105    while (1) {
106        msg.message = seL4_Recv(s->commonState.anonEP, &msg.badge);
107        timer_server_handle_message(s, &msg);
108        client_table_postaction(&s->commonState.clientTable);
109    }
110}
111
112uint32_t faketime() {
113    static uint32_t faketime = 0;
114    return faketime++;
115}
116
117/*! @brief Main timer server entry point. */
118int
119main()
120{
121    /* Future Work 3:
122       How the selfloader bootstraps user processes needs to be modified further. Changes were
123       made to accomodate the new way that muslc expects process's stacks to be set up when
124       processes start, but the one part of this that still needs to changed is how user processes
125       find their system call table. Currently the selfloader sets up user processes so that
126       the selfloader's system call table is used by user processes by passing the address of the
127       selfloader's system call table to the user processes via the user process's environment
128       variables. Ideally, user processes would use their own system call table.
129    */
130
131    uintptr_t address = strtoll(getenv("SYSTABLE"), NULL, 16);
132    refos_init_selfload_child(address);
133    dprintf("Initialising RefOS timer server.\n");
134    refosio_setup_morecore_override(timeServMMapRegion, TIMESERV_MMAP_REGION_SIZE);
135    refos_initialise_timer();
136    timeserv_init();
137
138    timer_server_mainloop();
139
140    return 0;
141}
142