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/dspace/stdio_dspace.h"
21#include "dispatchers/serv_dispatch.h"
22#include "dispatchers/client_watch.h"
23
24/*! @file
25    @brief Console Server main source file.
26
27    The RefOS Console server acts as a simple device driver server for basic system console input /
28    output functionality (eg. serial I/O for seeing things on the screen, EGA console output). It is
29    booted as a special system app in order for the system to to gain output functionality as early
30    as possible in the booting process. The only way to get output functionality before the console
31    server is up is to enable debug kernel mode and use seL4_DebugPutChar().
32
33    @image html conserv.png
34
35    The Console server:
36    <ul>
37        <li>Does NOT support providing pager service to clients.</li>
38        <li>Does NOT support providing content-initialisation for another dataserver.</li>
39        <li>Does NOT supports parameter buffers using an external dataspace (i.e. a dataspace
40            provided by another dataserver).</li>
41        <li>Does NOT support parameter buffers using an internal dataspace (i.e. a dataspace
42            provided the fileserver itself).</li>
43        <li>Does NOT support having its dataspace content-initalised by an external dataspace.</li>
44        <li>Ignores nBytes parameter in open() method (device IO doesn't have a file size).</li>
45    </ul>
46
47    The Console server provides the dataspaces: `/dev_console/serial` and `/dev/_console/screen`.
48    <ul>
49        <li>Writing to `/dev_console/serial` results in outputting to serial device.</li>
50        <li>Reading from `/dev_console/serial` results in reading from serial device.</li>
51        <li>Writing to `/dev_console/screen` results in outputting to EGA screen buffer.</li>
52        <li>Reading from `/dev_console/screen` is unsupported.</li>
53    </ul>
54*/
55
56/*! @brief Console server's static morecore region. */
57static char conServMMapRegion[CONSERV_MMAP_REGION_SIZE];
58
59/*! @brief Console server's system call table. */
60extern uintptr_t __vsyscall_ptr;
61
62/*! @brief Handle messages recieved by the Console server.
63    @param s The global Console server state. (No ownership transfer)
64    @param msg The recieved message. (No ownership transfer)
65    @return DISPATCH_SUCCESS if message dispatched, DISPATCH_ERROR if unknown message.
66*/
67static int
68console_server_handle_message(struct conserv_state *s, srv_msg_t *msg)
69{
70    int result = DISPATCH_PASS;
71    int label = seL4_GetMR(0);
72    void *userptr;
73
74    if (dispatch_client_watch(msg) == DISPATCH_SUCCESS) {
75        result = DISPATCH_SUCCESS;
76    }
77
78    if (dev_dispatch_interrupt(&s->irqState, msg) == DISPATCH_SUCCESS) {
79        result = DISPATCH_SUCCESS;
80    }
81
82    if (result == DISPATCH_SUCCESS) {
83        return result;
84    }
85
86    if (check_dispatch_data(msg, &userptr) == DISPATCH_SUCCESS) {
87        result = rpc_sv_data_dispatcher(userptr, label);
88        assert(result == DISPATCH_SUCCESS);
89        return DISPATCH_SUCCESS;
90    }
91
92    if (check_dispatch_serv(msg, &userptr) == DISPATCH_SUCCESS) {
93        result = rpc_sv_serv_dispatcher(userptr, label);
94        assert(result == DISPATCH_SUCCESS);
95        return DISPATCH_SUCCESS;
96    }
97
98    dprintf("Unknown message (badge = %d msgInfo = %d label = %d).\n",
99            msg->badge, seL4_MessageInfo_get_label(msg->message), label);
100    ROS_ERROR("Console server unknown message.");
101    assert("!Console server unknown message.");
102
103    return DISPATCH_ERROR;
104}
105
106/*! @brief Main console server message loop. Simply loops through recieving and dispatching messages
107           repeatedly. */
108static void
109console_server_mainloop(void)
110{
111    struct conserv_state *s = &conServ;
112    srv_msg_t msg;
113
114    while (1) {
115        msg.message = seL4_Recv(conServCommon->anonEP, &msg.badge);
116        console_server_handle_message(s, &msg);
117        client_table_postaction(&conServCommon->clientTable);
118    }
119}
120
121uint32_t faketime() {
122    static uint32_t faketime = 0;
123    return faketime++;
124}
125
126/*! @brief Main Console server entry point. */
127int
128main(void)
129{
130    /* Future Work 4:
131       Eventually RefOS should be changed so that processes that are started
132       by the process server do not require that the their system call table be
133       explicitly referenced in the code like this. Without expliciting referencing
134       __vsyscall_ptr in main(), the compiler optimizes away __vsyscall_ptr
135       and then processes started by the process server can't find their system call
136       table. Each of the four places in RefOS where this explicit reference is
137       required is affected by a custom linker script (linker.lds), so it is possible
138       that the custom linker script (and then likely other things too) needs to be
139       modified. Also note that the ROS_ERROR() and assert() inside this if statement
140       would not actually be able to execute if __vsyscall_ptr() were ever not set.
141       The purpose of these calls to ROS_ERROR() and assert() is to show future
142       developers that __vsyscall_ptr needs to be defined.
143    */
144    if (! __vsyscall_ptr) {
145        ROS_ERROR("Console server could not find system call table.");
146        assert("!Console server could not find system call table.");
147        return 0;
148    }
149
150    dprintf("Initialising RefOS Console server.\n");
151    refosio_setup_morecore_override(conServMMapRegion, CONSERV_MMAP_REGION_SIZE);
152    refos_initialise_os_minimal();
153    conserv_init();
154
155    console_server_mainloop();
156
157    return 0;
158}
159