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 Process Server anon RAM dataspace implementation.
15
16    A dataspace implementation which is backed by physical RAM. Provides methods for creating &
17    deleting ram dataspaces, as well as manages reading and writing to them directly. The actual
18    frames objects are lazily allocated. Dataspace objects support shared strong references through
19    refcounting.
20*/
21
22#ifndef _REFOS_PROCESS_SERVER_SYSTEM_MEMSERV_RAM_DATASPACE_H_
23#define _REFOS_PROCESS_SERVER_SYSTEM_MEMSERV_RAM_DATASPACE_H_
24
25#include <stdint.h>
26#include <stdbool.h>
27#include <sel4/sel4.h>
28#include <data_struct/cvector.h>
29#include <data_struct/coat.h>
30#include <vspace/vspace.h>
31#include "../../common.h"
32
33#define RAM_DATASPACE_MAGIC 0xF89D8531
34#define RAM_DATASPACE_LIST_MAGIC 0xC923BE76
35#define RAM_DATASPACE_WAITER_MAGIC 0x351095BC
36#define RAM_DATASPACE_INVALID_ID 0
37
38struct ram_dspace_list;
39
40/*! @brief Ram dataspace structure
41
42    A single ram dataspace backed by physical kernel pages. This structure assumes ownership of its
43    associated pages at all times.
44 */
45struct ram_dspace {
46    int ID;
47    uint32_t magic;
48    cspacepath_t capability;
49    uint32_t ref;
50
51    /* Anonymous RAM frames. */
52    vka_object_t *pages; /*< Has ownership. */
53    uint32_t npages;
54
55    /* Content init state. */
56    bool contentInitEnabled;
57    cspacepath_t contentInitEP;
58    uint32_t contentInitPID; /* No ownership. */
59    uint32_t *contentInitBitmask;
60    cvector_t contentInitWaitingList; /* ram_dspace_waiter */
61
62    /* Physical device state. */
63    bool physicalAddrEnabled;
64    uint32_t physicalAddr;
65
66    /*! Weak reference to this dataspace's parent. */
67    struct ram_dspace_list *parentList; /* No ownership. */
68};
69
70/*! @brief Ram dataspace list. */
71struct ram_dspace_list {
72    coat_t allocTable; /* struct ram_dspace */
73    uint32_t magic;
74};
75
76/*! @brief Ram dataspace content init waiter structure */
77struct ram_dspace_waiter {
78    int pageidx;
79    cspacepath_t reply;
80    uint32_t magic;
81};
82
83/* ------------------------------- RAM dataspace table functions -------------------------------- */
84
85/*! @brief Initialises an empty ram dataspace list. */
86void ram_dspace_init(struct ram_dspace_list *rdslist);
87
88/*! @brief De-initialises an empty ram dataspace list. */
89void ram_dspace_deinit(struct ram_dspace_list *rdslist);
90
91/*! @brief Creates a new ram dataspace and inserts into a ram dataspace list.
92    @param rdslist The ram dataspace list to allocate from.
93    @param size The size of the new dataspace in bytes.
94    @return The newly created ram dataspace if success (No ownership), NULL otherwise.
95 */
96struct ram_dspace *ram_dspace_create(struct ram_dspace_list *rdslist, size_t size);
97
98/*! @brief Adds a shared reference to ram dataspace from a ram dataspace list.
99    @param rdslist The ram dataspace list to reference the dataspace from.
100    @param ID The ID of target ram dataspace to be refed.
101 */
102void ram_dspace_ref(struct ram_dspace_list *rdslist, int ID);
103
104/*! @brief Unreference a ram dataspace from a ram dataspace list. If this is the last reference,
105           then the ram dataspace will be deleted from the list.
106    @param rdslist The ram dataspace list to unref the dataspace from.
107    @param ID The ID of target ram dataspace to be unrefed.
108 */
109void ram_dspace_unref(struct ram_dspace_list *rdslist, int ID);
110
111/*! @brief Checks whether a page in the ram dataspace exists, and finds & returns it if it does.
112    @param dataspace The ram dataspace to find and get the page object from.
113    @param offset Offset into the ram dataspace.
114    @return CPtr to frame if there's a page at the given offset in the given dataspace,
115            0 otherwise. No ownership transfer.
116 */
117seL4_CPtr ram_dspace_check_page(struct ram_dspace *dataspace, uint32_t offset);
118
119/*! @brief Retrieves a page at a given offset. If the page hasn't been created, it will be
120           allocated. Note that this does NOT perform content init.
121    @param dataspace The ram dataspace to get the page object from.
122    @param offset Offset into the ram dataspace.
123    @return CPtr to frame if success, 0 if offset invalid or out of memory. No ownership transfer.
124 */
125seL4_CPtr ram_dspace_get_page(struct ram_dspace *dataspace, uint32_t offset);
126
127/*! @brief Finds a ram dataspace in a ram dataspace list by a dataspace ID.
128    @param rdslist The source list of ram dataspaces. (No ownership)
129    @param ID The dataspace ID to locate the ram dataspace in the list.
130    @return The (weak) reference to target ram dataspace if found, NULL otherwise.
131 */
132struct ram_dspace *ram_dspace_get(struct ram_dspace_list *rdslist, int ID);
133
134/*! @brief Finds a ram dataspace in a ram dataspace list by a dataspace badge.
135    @param rdslist The source list of ram dataspaces. (No ownership)
136    @param badge The dataspace badge to locate the ram dataspace in the list.
137    @return The (weak) reference to target ram dataspace if found, NULL otherwise.
138 */
139struct ram_dspace *ram_dspace_get_badge(struct ram_dspace_list *rdslist, seL4_Word badge);
140
141/*! @brief Returns the size in bytes of the given dataspace.
142    @param dataspace The dataspace to retrieve size for.
143    @return Size of the given dataspace in bytes on success, 0 otherwise.
144*/
145uint32_t ram_dspace_get_size(struct ram_dspace *dataspace);
146
147/*! @brief Expands the given dataspace.
148    @param dataspace The dataspace to expand for.
149    @param size The new dataspace size.
150    @return ESUCCESS on success, refos_error otherwise.
151*/
152int ram_dspace_expand(struct ram_dspace *dataspace, uint32_t size);
153
154/*! @brief Sets the dataspace to start at the given physical address.
155
156    Sets the dataspace to start at the given physical address. The following pages of the
157    dataspace will be mapped to the following contiguous physical memory regions. Used to
158    implement device MMIO mapping. Requires the dataspace to be empty and not initialised by
159    any other content already.
160    This should be called immediately after dataspace creation.
161
162    @param dataspace The dataspace to set physical address for.
163    @param paddr The physical address to start the dataspace at.
164    @return ESUCCESS on success, refos_error otherwise.
165*/
166int ram_dspace_set_to_paddr(struct ram_dspace *dataspace, uint32_t paddr);
167
168/* --------------------------- RAM dataspace read / write functions ----------------------------- */
169
170/*! @brief Reads data from a ram dataspace.
171    @param buf The destination buffer to copy data to. (No ownership)
172    @param len The length of the data to be copied.
173    @param dataspace The source ram dataspace. (No ownership)
174    @param offset The offset into the dataspace to read from.
175    @return ESUCCESS if success, refos_error otherwise.
176 */
177int ram_dspace_read(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset);
178
179/*! @brief Writes data to a ram dataspace.
180    @param buf The source buffer containing the data. (No ownership)
181    @param len The length of the data to be written.
182    @param dataspace The target dataspace to be written to. (No ownership)
183    @param offset The offset into the dataspace to write to.
184    @return ESUCCESS if success, refos_error otherwise.
185 */
186int ram_dspace_write(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset);
187
188/* --------------------------- RAM dataspace content init functions ----------------------------- */
189
190/*! @brief Sets the RAM dataspace to be initialised by another RAM dataspace.
191    @param dataspace The dataspace set content init for.
192    @param initEP The external dspace server that will initialise this dataspace. (Takes ownership)
193    @param initPID The external dspace server PID.
194    @return ESUCCESS if success, refos_error otherwise.
195*/
196int ram_dspace_content_init(struct ram_dspace *dataspace, cspacepath_t initEP, uint32_t initPID);
197
198/*! @brief Returns whether content initialisation is needed for the given offset.
199    @param dataspace The target dataspace.
200    @param offset The offset into the dataspace to get content init state for.
201    @return TRUE if need content init at given offset, FALSE if already initialised, or -refos_error
202            if content init is not enabled for the given dataspace, or if offset is invalid.
203*/
204int ram_dspace_need_content_init(struct ram_dspace *dataspace, uint32_t offset);
205
206/*! @brief Add a new content-init blocked waiter.
207
208    Adds a new content-init waiter at the given offset to this dataspace. When the content
209    has been provided, the given endpoint will be replied to.
210
211    @param dataspace The dataspace that the waiter wants to wait on.
212    @param offset The offset at which the client is waiting for, into the dataspace.
213    @param reply The reply endpoint, which will unblock the waiting client.
214    @return ESUCCESS if success, refos_error otherwise.
215*/
216int ram_dspace_add_content_init_waiter(struct ram_dspace *dataspace, uint32_t offset,
217                                       cspacepath_t reply);
218
219/*! @brief Add a new content-init blocked waiter using current caller reply cap.
220    @param dataspace The dataspace that the waiter wants to wait on.
221    @param offset The offset at which the client is waiting for, into the dataspace.
222    @return ESUCCESS if success, refos_error otherwise.
223*/
224int ram_dspace_add_content_init_waiter_save_current_caller(struct ram_dspace *dataspace,
225                                                           uint32_t offset);
226
227/*! @brief Wakes up any waiters waiting at this offset.
228
229    Wakes up any waiter clients waiting at this offset for content-init. This does NOT set the
230    content provided flag, simply loops through the waiting list the replies to clients.
231
232    Note that we do not need to perform and VSpace mapping operations here on the waiting clients,
233    but simply waking them back up is enough, as they will cause another VM fault upon wake-up and
234    then since the content has been initialised now, it will me mapped straight in on the second VM
235    fault. This may be optimised further by performing VSpace mappings right now before waking up
236    the clients.
237
238    @param dataspace The dataspace containing the waiters.
239    @param offset The offset at which the clients are waiting for, into the dataspace.
240*/
241void ram_dspace_content_init_reply_waiters(struct ram_dspace *dataspace, uint32_t offset);
242
243/*! @brief Set the content-init page of dataspace at offset to be provided.
244
245    Set the provided bitmask flag of the dataspace at the offset to be TRUE, meaning that that page
246    has been content-init provided. Any waiters waiting for the content to be provided should now be
247    woken up, and any further access to these pages should not cause another content-init delegation
248    notification. Does NOT automatically reply to the waiters, that must be separately done via a
249    separate call to ram_dspace_content_init_reply_waiters().
250
251    @param dataspace The target dataspace.
252    @param offset The offset into the dataspace to get content init state for.
253*/
254void ram_dspace_set_content_init_provided(struct ram_dspace *dataspace, uint32_t offset);
255
256#endif /* _REFOS_PROCESS_SERVER_SYSTEM_MEMSERV_RAM_DATASPACE_H_ */