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/*! @file
14    @brief Top-level main module for process server.
15
16    The top level main module of the process server, containing the main function which runs as
17    the initial kernel thread. This function starts up the process server, bootstraps itself, initialises the
18    submodules, and starts the rest of system.
19
20    The process server is responsible for implementing threads and processes, managing memory window
21    segments, exposing anonymous memory dataspaces, and handing off other system resources to the available system
22    processes (such as device and IRQ caps device servers).
23
24    @image html procserv.png
25
26    The process server's anonymous dataspace implementation:
27    <ul>
28        <li>Assumes the connection session is set up, so therefore does not support connection
29            establishment.</li>
30        <li>Ignores the fileName parameter of the open method; makes no sense for anon memory.</li>
31        <li>Reads the nBytes parameter of the open method, as the maximum size of the ram dataspace
32            created. </li>
33        <li>Does NOT implement set_parambuffer, it shares the parambuffer from procserv interface
34            and reads that instead. </li>
35        <li>Supports the parambuffer (set in the procserv interface) coming from a ram dataspace
36            provided by the process server itself. </li>
37        <li>Does not support content initialisation via init_data. Process server cannot provide
38            content for another dataserver in the current implementation.</li>
39        <li>Does support have_data and provide_data. In other words, process server RAM dataspace
40            can have its content initialised by an external dataserver.</li>
41    </ul>
42*/
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <assert.h>
47
48#include <sel4platsupport/bootinfo.h>
49
50#include "common.h"
51#include "state.h"
52#include "test/test.h"
53#include "dispatchers/proc_syscall.h"
54#include "dispatchers/mem_syscall.h"
55#include "dispatchers/data_syscall.h"
56#include "dispatchers/name_syscall.h"
57#include "dispatchers/fault_handler.h"
58#include "system/process/process.h"
59
60/*! @brief Process server IPC message handler.
61
62    Handles dispatching of all process server IPC messages. Calls each individual dispatcher until
63    the correct dispatcher for the message type has been found.
64
65    @param s The process server global state.
66    @param msg The process server recieved message info.
67 */
68static void
69proc_server_handle_message(struct procserv_state *s, struct procserv_msg *msg)
70{
71    int result;
72    int label = seL4_GetMR(0);
73    void *userptr = NULL;
74    (void) result;
75
76    /* Attempt to dispatch to procserv syscall dispatcher. */
77    if (check_dispatch_syscall(msg, &userptr) == DISPATCH_SUCCESS) {
78        result = rpc_sv_proc_dispatcher(userptr, label);
79        assert(result == DISPATCH_SUCCESS);
80        mem_syscall_postaction();
81        proc_syscall_postaction();
82        return;
83    }
84
85    /* Attempt to dispatch to VM fault dispatcher. */
86    if (check_dispatch_fault(msg, &userptr) == DISPATCH_SUCCESS) {
87        result = dispatch_vm_fault(msg, &userptr);
88        assert(result == DISPATCH_SUCCESS);
89        return;
90    }
91
92    /* Attempt to dispatch to RAM dataspace syscall dispatcher. */
93    if (check_dispatch_dataspace(msg, &userptr) == DISPATCH_SUCCESS) {
94        result = rpc_sv_data_dispatcher(userptr, label);
95        assert(result == DISPATCH_SUCCESS);
96        mem_syscall_postaction();
97        return;
98    }
99
100    /* Attempt to dispatch to nameserv syscall dispatcher. */
101    if (check_dispatch_nameserv(msg, &userptr) == DISPATCH_SUCCESS) {
102        result = rpc_sv_name_dispatcher(userptr, label);
103        assert(result == DISPATCH_SUCCESS);
104        return;
105    }
106
107    /* Unknown message. Block calling client indefinitely. */
108    dprintf("Unknown message (badge = %d msgInfo = %d syscall = 0x%x).\n",
109            msg->badge, seL4_MessageInfo_get_label(msg->message), label);
110    ROS_ERROR("Process server unknown message. �����(��_o)/��");
111}
112
113/*! @brief Main process server loop.
114
115    The main loop that the process server goes into and keeps looping until the process server
116    is to exit and the whole system is to by shut down (which is possibly never). It blocks on the
117    process server endpoint and waits for an IPC message, and then handles the dispatching of
118    the message when it recieves one, before looping around and waiting for the next IPC message.
119
120    @return Does not return, runs endlessly.
121*/
122static int
123proc_server_loop(void)
124{
125    struct procserv_state *s = &procServ;
126    struct procserv_msg msg = { .state = s };
127
128    while (1) {
129        dvprintf("procserv blocking for new message...\n");
130        msg.message = seL4_Recv(s->endpoint.cptr, &msg.badge);
131        proc_server_handle_message(s, &msg);
132        s->faketime++;
133    }
134
135    return 0;
136}
137
138/*! @brief Process server main entry point. */
139int
140main(void)
141{
142    initialise(platsupport_get_bootinfo(), &procServ);
143    dprintf("======== RefOS Process Server ========\n");
144
145    // -----> Run Root Task Testing.
146    #ifdef CONFIG_REFOS_RUN_TESTS
147        test_run_all();
148    #endif
149
150    // -----> Start RefOS system processes.
151    int error;
152
153    error = proc_load_direct("console_server", 252, "", PID_NULL,
154            PROCESS_PERMISSION_DEVICE_IRQ | PROCESS_PERMISSION_DEVICE_MAP |
155            PROCESS_PERMISSION_DEVICE_IOPORT);
156    if (error) {
157        ROS_WARNING("Procserv could not start console_server.");
158        assert(!"RefOS system startup error.");
159    }
160
161    error = proc_load_direct("file_server", 250, "", PID_NULL, 0x0);
162    if (error) {
163        ROS_WARNING("Procserv could not start file_server.");
164        assert(!"RefOS system startup error.");
165    }
166
167    // -----> Start OS level tests.
168    #ifdef CONFIG_REFOS_RUN_TESTS
169        error = proc_load_direct("test_os", 245, "", PID_NULL, 0x0);
170        if (error) {
171            ROS_WARNING("Procserv could not start test_os.");
172            assert(!"RefOS system startup error.");
173        }
174    #endif
175
176    // -----> Start RefOS timer server.
177    error = proc_load_direct("selfloader", 245, "fileserv/timer_server", PID_NULL,
178            PROCESS_PERMISSION_DEVICE_IRQ | PROCESS_PERMISSION_DEVICE_MAP |
179            PROCESS_PERMISSION_DEVICE_IOPORT);
180    if (error) {
181        ROS_WARNING("Procserv could not start timer_server.");
182        assert(!"RefOS system startup error.");
183    }
184
185    // -----> Start initial task.
186    if (strlen(CONFIG_REFOS_INIT_TASK) > 0) {
187        error = proc_load_direct("selfloader", CONFIG_REFOS_INIT_TASK_PRIO, CONFIG_REFOS_INIT_TASK,
188                                 PID_NULL, 0x0);
189        if (error) {
190            ROS_WARNING("Procserv could not start initial task.");
191            assert(!"RefOS system startup error.");
192        }
193    }
194
195    return proc_server_loop();
196}
197