1/* 2 * Copyright 2017, 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(DATA61_BSD) 11 */ 12 13/* Error handling API for CAmkES. */ 14 15#pragma once 16 17#include <autoconf.h> 18#include <sel4camkes/gen_config.h> 19#include <sel4/sel4.h> 20#include <stdbool.h> 21#include <stdint.h> 22#include <stdlib.h> 23#include <utils/util.h> 24 25/* Types of errors that can occur in CAmkES glue code. */ 26typedef enum { 27 28 /* No error occurred. Used to indicate normal operation. */ 29 CE_NO_ERROR = 0, 30 31 /* During marshalling, the next operation if we were to continue would 32 * exceed the size of the target buffer. Note that continuing in the event 33 * of such an error *will* cause an out-of-bounds memory write. 34 */ 35 CE_BUFFER_LENGTH_EXCEEDED, 36 37 /* In an RPC communication, the method index indicated by the caller was 38 * out of range for the given interface. That is, the method index was 39 * larger than the number of methods in this interface, or it was negative. 40 */ 41 CE_INVALID_METHOD_INDEX, 42 43 /* The payload of an RPC (marshalled parameters) was somehow invalid. This 44 * includes cases where an IPC recipient received a message that was either 45 * too long or too short for what it was expecting. 46 */ 47 CE_MALFORMED_RPC_PAYLOAD, 48 49 /* A system call that is never expected to fail in normal operation, did 50 * so. Recovery actions are most likely dependent on what and where the 51 * actual failure was. 52 */ 53 CE_SYSCALL_FAILED, 54 55 /* Some internal memory/bookkeeping allocation the glue code needed to 56 * perform did not complete successfully. It will be difficult to diagnose 57 * the cause of one of these without looking at the location at which the 58 * error was triggered. 59 */ 60 CE_ALLOCATION_FAILURE, 61 62 /* A counter would overflow or underflow if execution were to continue from 63 * the current point. 64 */ 65 CE_OVERFLOW, 66 67} camkes_error_type_t; 68 69/* Tagged union representing data about an error itself. */ 70typedef struct { 71 /* The type of the error. This tag determines which member of the union 72 * below is relevant. 73 */ 74 camkes_error_type_t type; 75 76 /* The component instance in which this error occurred. This will probably 77 * never be ambiguous programmatically, but it may be useful to have this 78 * value available to print. Error handlers can assumes this pointer will 79 * never be NULL. 80 */ 81 const char *instance; 82 83 /* The interface in which this error occurred. If this error occurred in a 84 * component-global context then this pointer will be NULL. 85 */ 86 const char *interface; 87 88 /* The source code position at which the error occurred. Useful if you are 89 * debugging template generation. 90 */ 91 const char *filename; 92 long lineno; 93 94 /* A human readable description of the failure. Error handlers can assume 95 * this pointer will never be NULL. 96 */ 97 const char *description; 98 99 union { 100 /* No union member for CE_NO_ERROR. */ 101 102 struct { /* CE_BUFFER_LENGTH_EXCEEDED */ 103 104 /* The current byte offset into the buffer. */ 105 unsigned current_length; 106 107 /* The byte offset we're about to reach if we perform the next 108 * write. I.e. an offset out-of-bounds of the buffer itself. 109 */ 110 unsigned target_length; 111 }; 112 113 struct { /* CE_INVALID_METHOD_INDEX */ 114 115 /* The range of valid method indices. */ 116 uint64_t lower_bound; 117 uint64_t upper_bound; 118 119 /* The value that caused this error. */ 120 uint64_t invalid_index; 121 }; 122 123 struct { /* CE_MALFORMED_RPC_PAYLOAD */ 124 125 /* The (possibly invalid) length of the payload. */ 126 unsigned length; 127 128 /* The current byte offset into the buffer. I.e. the point at which 129 * we realised we had an invalid payload. 130 */ 131 unsigned current_index; 132 }; 133 134 struct { /* CE_SYSCALL_FAILED */ 135 136 /* The syscall that we ran. This value will be a member of 137 * invocation_label or arch_invocation_label from libsel4. 138 */ 139 int syscall; 140 141 /* The error value returned by seL4. */ 142 int error; 143 }; 144 145 struct { /* CE_ALLOCATION_FAILURE */ 146 147 /* The number of bytes that was being allocated when the failure 148 * occurred. This field may be zero if the amount was not relevant. 149 */ 150 size_t alloc_bytes; 151 }; 152 }; 153} camkes_error_t; 154 155/* The action to take to recover from an error. An error handler, as described 156 * below, should return one of these values to indicate what action the glue 157 * code should take. 158 */ 159typedef enum { 160 161 /* Used as a sentinel for a context where an action is invalid. Don't ever 162 * return this from an error handler. 163 */ 164 CEA_INVALID = -1, 165 166 /* Terminate the currently running piece of glue code by returning. If the 167 * offending code was called from a glue code event loop, this generally 168 * means return to the event loop. If the offending code was called from 169 * user code, this means return to user code where the calling function is 170 * expected to be aware (by some out-of-band communication) that an error 171 * has occurred. 172 */ 173 CEA_DISCARD, 174 175 /* Ignore the error and continue. This is generally dangerous and not what 176 * you want. 177 */ 178 CEA_IGNORE, 179 180 /* Exit with failure in the current thread. Note that what 'exit' means 181 * here depends on a number of things including whether the thread has a 182 * cap to itself. 183 */ 184 CEA_ABORT, 185 186 /* Exit with failure and also try to halt the entire system if possible. 187 * This action implies CEA_ABORT and only differs on a debug kernel where 188 * it is possible to stop the system. If you have no error handlers 189 * installed, this is the default action. 190 */ 191 CEA_HALT, 192 193} camkes_error_action_t; 194 195/* An error handling function. If components define their own error handlers, 196 * they should conform to this prototype. The argument is the error that 197 * occurred and the return value is the recovery action the glue code should 198 * take. 199 */ 200typedef camkes_error_action_t (*camkes_error_handler_t)(camkes_error_t *); 201 202/* Register a component-global error handler. More fine-grained registration 203 * functions (one per-interface) are generated and prototyped in the generated 204 * header. Errors that occur in interface glue code will only invoke this error 205 * handler if no error handler is registered for the interface itself. This 206 * registration function returns a pointer to the old handler. 207 */ 208camkes_error_handler_t camkes_register_error_handler( 209 camkes_error_handler_t handler); 210 211/* Throw an error from glue code. This function is not expected to be called by 212 * user code. 213 */ 214camkes_error_action_t camkes_error(camkes_error_t *e) COLD; 215 216/* Convenience for using halt() inside macro definitions. This is not expected 217 * to be called from user code. Note that it does not halt on a non-debug 218 * kernel. 219 */ 220#ifdef CONFIG_DEBUG_BUILD 221#define halt() seL4_DebugHalt() 222#else 223#define halt() do { } while (0) 224#endif 225 226#ifdef CONFIG_CAMKES_ERROR_HANDLER_CONFIGURABLE 227 228/* Convenience macro for throwing an error from glue code. 229 * handler - A camkes_error_handler_t to invoke. 230 * edata - Error structure to throw to the error handler. 231 * action - Action to take on return of CEA_DISCARD from the error 232 * handler. This should be a GNU statement expression (aka compound 233 * statement). 234 */ 235#define ERR(handler, edata, action) ({ \ 236 COLD_PATH(); \ 237 camkes_error_t _e = edata; \ 238 _e.filename = __FILE__; \ 239 _e.lineno = __LINE__; \ 240 switch (handler(&_e)) { \ 241 case CEA_DISCARD: \ 242 action; \ 243 UNREACHABLE(); \ 244 case CEA_IGNORE: \ 245 break; \ 246 case CEA_HALT: \ 247 halt(); \ 248 /* If we return we'll just fall through. */ \ 249 case CEA_ABORT: \ 250 abort(); \ 251 /* In case we return */ \ 252 while(1); \ 253 default: \ 254 UNREACHABLE(); \ 255 } \ 256 }) 257 258#elif defined(CONFIG_CAMKES_ERROR_HANDLER_GUARD) 259 260#define ERR(handler, edata, action) GUARD(false) 261 262#elif defined(CONFIG_CAMKES_ERROR_HANDLER_ABORT) 263 264#define ERR(handler, edata, action) abort() 265 266#elif defined(CONFIG_CAMKES_ERROR_HANDLER_DISCARD) 267 268#define ERR(handler, edata, action) action 269 270#else 271 272#error no error handling mode defined 273 274#endif 275 276#ifdef CONFIG_CAMKES_ERROR_HANDLER_GUARD 277 278#define ERR_IF(cond, handler, edata, action) GUARD(!(cond)) 279 280#else 281 282/* Conditionally throw an error. */ 283#define ERR_IF(cond, handler, edata, action) ({ \ 284 if (unlikely(cond)) { \ 285 ERR(handler, edata, action); \ 286 } \ 287 }) 288 289#endif 290