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 CPIO File Server main source file.
15
16    The main role of the fileserver in the system is to provide the executable file contents via
17    the dataspace interface. It does some book-keeping and simple management of clients.
18
19    @image html fileserv.png
20
21    The CPIO file server:
22    <ul>
23        <li>Supports providing pager service to clients.</li>
24        <li>Supports providing content-initialisation for another dataserver.</li>
25        <li>Supports parameter buffers using an external dataspace (i.e. a dataspace provided by
26            another dataserver).</li>
27        <li>Does NOT support parameter buffers using an internal dataspace (i.e. a dataspace
28            provided the fileserver itself).</li>
29        <li>Does NOT support having its dataspace content-initalised by an external dataspace.</li>
30        <li>Ignores nBytes parameter in open() method (actual CPIO file size is used).</li>
31    </ul>
32
33    The CPIO file server provides access to files stored in a CPIO archive inside the server.
34    The CPIO archive is a simple format file archive stored inside a parent program's ELF section.
35    This is a similar idea to something like creating a
36    > const char data[] = { 0x3F, 0xFF, 0x23 ...etc}
37
38    The CPIO file server is used to store the RefOS userland app ELF binaries, and any additional
39    data files. It provides a simple example of a dataserver, and may serve as the means to boot
40    more complex dataspace servers involving flash memory / SATA drivers and so forth.
41*/
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <assert.h>
46#include <sel4/sel4.h>
47#include <cpio/cpio.h>
48
49#include <refos/refos.h>
50#include <refos-io/morecore.h>
51#include <refos-io/stdio.h>
52#include <refos-util/init.h>
53#include <refos-util/serv_connect.h>
54
55#include "state.h"
56#include "dispatchers/dispatch.h"
57#include "dispatchers/serv_dispatch.h"
58#include "dispatchers/cpio_dspace.h"
59#include "dispatchers/fault_notify.h"
60
61#define MMAP_SIZE 0x200000 /*!< 32MB.. */
62static char mmapRegion[MMAP_SIZE];
63
64/*! @brief File server's system call table. */
65extern uintptr_t __vsyscall_ptr;
66
67/*! @brief Fake time generator used by dprintf(). */
68uint32_t faketime() {
69    static uint32_t _faketime = 0;
70    return _faketime++;
71}
72
73/*! @brief Handle messages received by the CPIO file server.
74    @param s The global file server state. (No ownership transfer)
75    @param msg The received message. (No ownership transfer)
76    @return DISPATCH_SUCCESS if message dispatched, DISPATCH_ERROR if unknown message.
77*/
78static int
79fileserv_handle_message(struct fs_state *s, srv_msg_t *msg)
80{
81    int result;
82    int label = seL4_GetMR(0);
83    void *userptr;
84    (void) result;
85
86    if (dispatch_notification(msg) == DISPATCH_SUCCESS) {
87        return DISPATCH_SUCCESS;
88    }
89
90    if (check_dispatch_serv(msg, &userptr) == DISPATCH_SUCCESS) {
91        result = rpc_sv_serv_dispatcher(userptr, label);
92        assert(result == DISPATCH_SUCCESS);
93        return DISPATCH_SUCCESS;
94    }
95
96    if (check_dispatch_data(msg, &userptr) == DISPATCH_SUCCESS) {
97        result = rpc_sv_data_dispatcher(userptr, label);
98        assert(result == DISPATCH_SUCCESS);
99        return DISPATCH_SUCCESS;
100    }
101
102    dprintf("Unknown message (badge = %d msgInfo = %d label = %d (0x%x)).\n",
103            msg->badge, seL4_MessageInfo_get_label(msg->message), label, label);
104    ROS_ERROR("File server unknown message.");
105    assert(!"File server unknown message.");
106
107    return DISPATCH_ERROR;
108}
109
110/*! @brief Main CPIO file server message loop. Simply loops through recieving and dispatching
111           messages repeatedly. */
112static void
113fileserv_mainloop(void)
114{
115    struct fs_state *s = &fileServ;
116    srv_msg_t msg;
117
118    while (1) {
119        dvprintf("Fileserver blocking for message...\n");
120        msg.message = seL4_Recv(fileServCommon->anonEP, &msg.badge);
121        fileserv_handle_message(s, &msg);
122        client_table_postaction(&fileServCommon->clientTable);
123    }
124}
125
126/*! @brief Main CPIO file server entry point. */
127int
128main()
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("File server could not find system call table.");
146        assert("!File server could not find system call table.");
147        return 0;
148    }
149
150    refosio_setup_morecore_override(mmapRegion, MMAP_SIZE);
151    refos_initialise_os_minimal();
152    refos_setup_dataspace_stdio(REFOS_DEFAULT_STDIO_DSPACE);
153
154    fileserv_init();
155    fileserv_mainloop();
156
157    return 0;
158}
159