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 "state.h" 14#include "common.h" 15#include <simple/simple.h> 16#include <sel4platsupport/platsupport.h> 17#include <sel4platsupport/plat/serial.h> 18#include <sel4debug/debug.h> 19#include <autoconf.h> 20#include <refos/refos.h> 21#include <refos-rpc/rpc.h> 22 23/*! @file 24 @brief Global statuc struct & helper functions for process server. */ 25 26#define PROCSERV_IRQ_HANDLER_HASHTABLE_SIZE 32 27#define ALLOCATOR_VIRTUAL_POOL_SIZE ((1 << seL4_PageBits) * 100) 28#ifndef CONFIG_PROCSERV_INITIAL_MEM_SIZE 29 #define CONFIG_PROCSERV_INITIAL_MEM_SIZE (4096 * 32) 30#endif 31 32void *serial_paddr; 33static char _procservInitialMemPool[CONFIG_PROCSERV_INITIAL_MEM_SIZE]; 34struct procserv_state procServ; 35const char* dprintfServerName = "PROCSERV"; 36int dprintfServerColour = 32; 37 38uint32_t faketime() { 39 return procServ.faketime++; 40} 41 42static void procserv_nameserv_callback_free_cap(seL4_CPtr cap); 43 44/*! @brief display a heartwarming welcome message. 45 @param info The Bootinfo structure. 46*/ 47static void 48initialise_welcome_message(seL4_BootInfo *info) 49{ 50 dprintf("================= RefOS Version 2.0 =================\n"); 51 dprintf(" Built on "__DATE__" "__TIME__".\n"); 52 dprintf(" �� Copyright 2016 Data61, CSIRO\n"); 53 dprintf("=====================================================\n"); 54 55 debug_print_bootinfo(info); 56} 57 58/*! @brief Initialises the kernel object allocator. 59 @param info The BootInfo struct passed in from the kernel. 60 @param s The process server global state. 61 */ 62static void 63initialise_allocator(seL4_BootInfo *info, struct procserv_state *s) 64{ 65 assert(info && s); 66 int error = -1; 67 memset(s, 0, sizeof(struct procserv_state)); 68 (void) error; 69 reservation_t virtual_reservation; 70 /* Create and initialise allocman allocator, and create a virtual kernel allocator (VKA) 71 interface from it. */ 72 s->allocman = bootstrap_use_bootinfo(info, CONFIG_PROCSERV_INITIAL_MEM_SIZE, 73 _procservInitialMemPool); 74 assert(s->allocman); 75 allocman_make_vka(&s->vka, s->allocman); 76 s->vkaPtr = &s->vka; 77 78 /* Manage our own root server VSpace using this newly created allocator. */ 79 error = sel4utils_bootstrap_vspace_with_bootinfo_leaky(&s->vspace, &s->vspaceData, 80 seL4_CapInitThreadPD, &s->vka, info); 81 assert(!error); 82 83 void *vaddr; 84 virtual_reservation = vspace_reserve_range(&s->vspace, 85 ALLOCATOR_VIRTUAL_POOL_SIZE, seL4_AllRights, 1, &vaddr); 86 87 if (virtual_reservation.res == 0) { 88 ZF_LOGF("Failed to provide virtual memory for allocator"); 89 } 90 91 bootstrap_configure_virtual_pool(s->allocman, vaddr, 92 ALLOCATOR_VIRTUAL_POOL_SIZE, seL4_CapInitThreadPD); 93 94 simple_default_init_bootinfo(&s->simpleEnv, info); 95} 96 97/*! @brief Initialise the process server modules. 98 @param s The process server global state. 99 */ 100static void 101initialise_modules(struct procserv_state *s) 102{ 103 pd_init(&s->PDList); 104 pid_init(&s->PIDList); 105 w_init(&s->windowList); 106 ram_dspace_init(&s->dspaceList); 107 nameserv_init(&s->nameServRegList, procserv_nameserv_callback_free_cap); 108} 109 110#ifdef CONFIG_ARCH_ARM 111/*! @brief Wrapper function for allocating a portion of an untyped into an object. 112 @param data cookie for the underlying allocator. 113 @param dest path to an empty cslot to place the cap to the allocated object. 114 @param type the seL4 object type to allocate (as passed to Untyped_Retype). 115 @param size_bits the size of the object to allocate (as passed to Untyped_Retype). 116 @param paddr The desired physical address that this object should start at. 117 @param cookie pointer to a location to store the cookie representing this allocation. 118 @return 0 on success. 119*/ 120static int 121serial_utspace_alloc_at_fn(void *data, const cspacepath_t *dest, seL4_Word type, 122 seL4_Word size_bits, uintptr_t paddr, seL4_Word *cookie) 123{ 124 /* since DEFAULT_SERIAL_PADDR memory has already been allocated, we do not 125 allocate it again */ 126 if ((uintptr_t) serial_paddr == paddr) { 127 return vka_cnode_copy(dest, &procServ.serial_frame_cap_path, seL4_AllRights); 128 } 129 130 assert(procServ.vka.utspace_alloc_at); 131 return procServ.vka.utspace_alloc_at(data, dest, type, size_bits, paddr, cookie); 132} 133 134/*! @brief Wrapper function for getting the cap to the physical frame of 135 memory and putting it at specified location. 136 @param data cookie for the underlying implementation. 137 @param paddr aligned physical address. 138 @param size_bits of the region in bits. 139 @param path The path to where to put this cap. 140*/ 141seL4_Error 142serial_get_frame_cap(void *data, void *paddr, int size_bits, cspacepath_t *path) 143{ 144 /* since DEFAULT_SERIAL_PADDR has already been initialised, we do not 145 initialise it again */ 146 if ((void *) serial_paddr == paddr) { 147 return vka_cnode_copy(path, &procServ.serial_frame_cap_path, seL4_AllRights); 148 } 149 150 return procServ.original_simple_get_frame_cap(data, paddr, size_bits, path); 151} 152#endif /* CONFIG_ARCH_ARM */ 153 154/*! @brief Initialise the process server. 155 @param info The BootInfo struct passed in from the kernel. 156 @param s The process server global state to initialise. 157 */ 158void 159initialise(seL4_BootInfo *info, struct procserv_state *s) 160{ 161 initialise_allocator(info, s); 162 int error; 163 (void) error; 164 165 vka_t serial_vka = s->vka; 166 167#ifdef CONFIG_ARCH_ARM 168 /* create wrapper functions for initialising DEFAULT_SERIAL_PADDR 169 since it has already been set up */ 170 vka_object_t result; 171 serial_paddr = (void *) DEFAULT_SERIAL_PADDR; 172 error = vka_alloc_frame_at(&s->vka, PAGE_BITS_4K, DEFAULT_SERIAL_PADDR, &result); 173 vka_cspace_make_path(&s->vka, result.cptr, &s->serial_frame_cap_path); 174 175 serial_vka.utspace_alloc_at = serial_utspace_alloc_at_fn; 176 177 s->original_simple_get_frame_cap = s->simpleEnv.frame_cap; 178 179 s->simpleEnv.frame_cap = serial_get_frame_cap; 180#endif /* CONFIG_ARCH_ARM */ 181 182 /* Enable printf and then print welcome message. */ 183 platsupport_serial_setup_simple(&s->vspace, &s->simpleEnv, &serial_vka); 184 initialise_welcome_message(info); 185 186 /* Set up process server global objects. */ 187 dprintf("Allocating main process server endpoint...\n"); 188 error = vka_alloc_endpoint(&s->vka, &s->endpoint); 189 assert(!error); 190 191 /* Initialise recieving cslot. */ 192 dprintf("Setting recv cslot...\n"); 193 error = vka_cspace_alloc_path(&s->vka, &s->IPCCapRecv); 194 assert(!error); 195 rpc_setup_recv_cspace(s->IPCCapRecv.root, s->IPCCapRecv.capPtr, s->IPCCapRecv.capDepth); 196 197 /* Initialise miscellaneous states. */ 198 dprintf("Initialising process server modules...\n"); 199 initialise_modules(s); 200 chash_init(&s->irqHandlerList, PROCSERV_IRQ_HANDLER_HASHTABLE_SIZE); 201 s->unblockClientFaultPID = PID_NULL; 202 203 /* Procserv initialised OK. */ 204 dprintf("PROCSERV initialised.\n"); 205 dprintf("==========================================\n\n"); 206} 207 208cspacepath_t 209procserv_mint_badge(int badge) 210{ 211 cspacepath_t path, pathSrc; 212 memset(&path, 0, sizeof(cspacepath_t)); 213 int error = vka_cspace_alloc_path(&procServ.vka, &path); 214 if (error) { 215 ROS_WARNING("procserv_mint_badge could not allocate a cslot."); 216 return path; 217 } 218 vka_cspace_make_path(&procServ.vka, procServ.endpoint.cptr, &pathSrc); 219 error = vka_cnode_mint( 220 &path, &pathSrc, seL4_NoRead, 221 seL4_CapData_Badge_new(badge) 222 ); 223 if (error) { 224 ROS_WARNING("procserv_mint_badge could not mint endpoint cap."); 225 vka_cspace_free(&procServ.vka, path.capPtr); 226 memset(&path, 0, sizeof(cspacepath_t)); 227 return path; 228 } 229 return path; 230} 231 232int 233procserv_frame_write(seL4_CPtr frame, const char* src, size_t len, size_t offset) 234{ 235 if (offset + len > REFOS_PAGE_SIZE) { 236 ROS_ERROR("procserv_frame_write invalid offset and length."); 237 return EINVALIDPARAM; 238 } 239 char* addr = (char*) vspace_map_pages(&procServ.vspace, &frame, NULL, seL4_AllRights, 1, 240 seL4_PageBits, true); 241 if (!addr) { 242 ROS_ERROR ("procserv_frame_write couldn't map frame."); 243 return ENOMEM; 244 } 245 memcpy((void*)(addr + offset), (void*) src, len); 246 procserv_flush(&frame, 1); 247 vspace_unmap_pages(&procServ.vspace, addr, 1, seL4_PageBits, VSPACE_PRESERVE); 248 return ESUCCESS; 249} 250 251int 252procserv_frame_read(seL4_CPtr frame, const char* dst, size_t len, size_t offset) 253{ 254 if (offset + len > REFOS_PAGE_SIZE) { 255 ROS_ERROR("procserv_frame_read invalid offset and length."); 256 return EINVALIDPARAM; 257 } 258 259 char* addr = (char*) vspace_map_pages(&procServ.vspace, &frame, NULL, seL4_AllRights, 1, 260 seL4_PageBits, true); 261 if (!addr) { 262 ROS_ERROR ("procserv_frame_read couldn't map frame."); 263 return ENOMEM; 264 } 265 procserv_flush(&frame, 1); 266 memcpy((void*) dst, (void*)(addr + offset), len); 267 vspace_unmap_pages(&procServ.vspace, addr, 1, seL4_PageBits, VSPACE_PRESERVE); 268 return ESUCCESS; 269} 270 271/*! @brief The free EP cap callback function, used by the nameserv implementation helper library. 272 @param cap The endpoint cap to free. 273 */ 274static void 275procserv_nameserv_callback_free_cap(seL4_CPtr cap) 276{ 277 if (!cap) { 278 ROS_WARNING("procserv_nameserv_callback_free_cap called on NULL cap!"); 279 return; 280 } 281 cspacepath_t path; 282 vka_cspace_make_path(&procServ.vka, cap, &path); 283 284 /* Name server service does not revoke the given anon caps, clients get to keep them. */ 285 vka_cnode_delete(&path); 286 vka_cspace_free(&procServ.vka, cap); 287} 288 289cspacepath_t 290procserv_find_device(void *paddr, int size) 291{ 292 cspacepath_t path; 293 path.capPtr = 0; 294 295 /* Figure out device size in bits. */ 296 int sizeBits = -1; 297 for (int i = 0; i < 32; i++) { 298 if ((1 << i) == size) { 299 sizeBits = i; 300 break; 301 } 302 } 303 if (sizeBits == -1) { 304 ROS_ERROR("procserv_find_device invalid size 0x%x!\n", size); 305 return path; 306 } 307 308 /* Allocate a cslot. */ 309 int error = vka_cspace_alloc_path(&procServ.vka, &path); 310 if (error) { 311 ROS_ERROR("procserv_find_device failed to allocate cslot."); 312 path.capPtr = 0; 313 return path; 314 } 315 316 /* Perform the device lookup. */ 317 error = simple_get_frame_cap(&procServ.simpleEnv, paddr, sizeBits, &path); 318 if (error) { 319 vka_cspace_free(&procServ.vka, path.capPtr); 320 path.capPtr = 0; 321 return path; 322 } 323 324 assert(path.capPtr); 325 return path; 326} 327 328void 329procserv_flush(seL4_CPtr *frame, int nFrames) 330{ 331#ifdef CONFIG_ARCH_ARM 332 if (!frame) { 333 return; 334 } 335 for (int i = 0; i < nFrames; i++) { 336 if (!frame[i]) { 337 continue; 338 } 339 seL4_ARM_Page_Unify_Instruction(frame[i], 0, REFOS_PAGE_SIZE); 340 } 341#endif /* CONFIG_ARCH_ARM */ 342} 343 344seL4_CPtr 345procserv_get_irq_handler(int irq) 346{ 347 /* Check whether we have already made a handler for this IRQ. */ 348 seL4_CPtr existingHandler = (seL4_CPtr) chash_get(&procServ.irqHandlerList, irq); 349 if (existingHandler) { 350 return existingHandler; 351 } 352 353 /* Allocate a new cslot to store the IRQ handler. */ 354 cspacepath_t handler; 355 int error = vka_cspace_alloc_path(&procServ.vka, &handler); 356 if (error) { 357 ROS_WARNING("procserv_get_irq_handler could not allocate IRQ handler cslot."); 358 return (seL4_CPtr) 0; 359 } 360 361 /* Get the handler. */ 362 error = seL4_IRQControl_Get(seL4_CapIRQControl, irq, 363 handler.root, handler.capPtr, handler.capDepth); 364 if (error) { 365 ROS_WARNING("procserv_get_irq_handler could not get IRQ handler for irq %u.\n", irq); 366 vka_cspace_free(&procServ.vka, handler.capPtr); 367 return (seL4_CPtr) 0; 368 } 369 370 chash_set(&procServ.irqHandlerList, irq, (chash_item_t) handler.capPtr); 371 372 return handler.capPtr; 373} 374