1/* @title: Error Codes */
2#pragma once
3#include <compiler/core.h>
4#include <console/panic.h>
5#include <enforce.h>
6#include <linker/symbols.h>
7#include <stdarg.h>
8#include <stdint.h>
9#include <stringify.h>
10
11#define ERR_IS_FATAL(e) (e != ERR_OK && e != ERR_AGAIN)
12
13#define ERR_IS_MATCH_1(v, a) ((v) == (a))
14#define ERR_IS_MATCH_2(v, a, b) (ERR_IS_MATCH_1(v, a) || ((v) == (b)))
15#define ERR_IS_MATCH_3(v, a, b, c) (ERR_IS_MATCH_2(v, a, b) || ((v) == (c)))
16#define ERR_IS_MATCH_4(v, a, b, c, d) \
17 (ERR_IS_MATCH_3(v, a, b, c) || ((v) == (d)))
18#define ERR_IS_MATCH_5(v, a, b, c, d, e) \
19 (ERR_IS_MATCH_4(v, a, b, c, d) || ((v) == (e)))
20#define ERR_IS_MATCH_6(v, a, b, c, d, e, f) \
21 (ERR_IS_MATCH_5(v, a, b, c, d, e) || ((v) == (f)))
22#define ERR_IS_MATCH_7(v, a, b, c, d, e, f, g) \
23 (ERR_IS_MATCH_6(v, a, b, c, d, e, f) || ((v) == (g)))
24#define ERR_IS_MATCH_8(v, a, b, c, d, e, f, g, h) \
25 (ERR_IS_MATCH_7(v, a, b, c, d, e, f, g) || ((v) == (h)))
26
27#define ERR_GUARD(val, ...) \
28 ({ \
29 __auto_type _v = (val); \
30 if (cc_unlikely(_v < 0 && !PP_OVERLOAD(ERR_IS_MATCH, \
31 __VA_ARGS__)(_v, __VA_ARGS__))) \
32 panic("unhandled error: %s", errno_to_str(_v)); \
33 _v; \
34 })
35
36/* When this enum err is negated, i.e. becomes positive, the upper 16 bits
37 * indicate the *facility*. With 0, it's just one of these, but if it's > 0,
38 * it came from a specific subsystem that defined a struct err_facility */
39enum err {
40 ERR_OK = 0, // Success
41 ERR_UNKNOWN = -1, // Unknown or unspecified error
42 ERR_NO_MEM = -2, // Out of memory
43 ERR_NO_DEV = -3, // No such device
44 ERR_NO_ENT = -4, // No such file or directory
45 ERR_EXIST = -5, // File already exists
46 ERR_IO = -6, // I/O error
47 ERR_NOT_DIR = -7, // Not a directory
48 ERR_IS_DIR = -8, // Is a directory
49 ERR_INVAL = -9, // Invalid argument
50 ERR_PERM = -10, // Permission denied
51 ERR_FAULT = -11, // Bad address
52 ERR_BUSY = -12, // Resource/device busy
53 ERR_AGAIN = -13, // Try again later
54 ERR_NOT_IMPL = -14, // Not implemented
55 ERR_NOSPC = -15, // No space left on device
56 ERR_OVERFLOW = -16, // Value too large
57 ERR_NOT_EMPTY = -17, // Directory not empty
58
59};
60
61struct err_facility {
62 uint16_t prefix;
63 const char *name;
64 const char *desc;
65 const char *(*const to_str)(uint16_t delta);
66};
67
68/* Deltas must always be positive */
69#define ERR_CREATE(pre, del) \
70 ({ \
71 enforce((del & 0xFFFF) == del); \
72 enforce(del > 0); \
73 -((((int) (pre)) << 16) | (((int) (del)) & 0xFFFF)); \
74 })
75
76#define ERR_GET_FACILITY(e) \
77 ({ \
78 enforce(e < 0); \
79 ((-(e)) >> 16) & 0xFFFF; \
80 })
81
82#define ERR_GET_DELTA(e) \
83 ({ \
84 enforce(e < 0); \
85 ((-(e)) & 0xFFFF); \
86 })
87
88#define ERR_PREFIX(n) ((__err_facility_##n).prefix)
89#define ERR_DELTA_START (1)
90#define ERR(n, d) ERR_CREATE(ERR_PREFIX(n), d)
91
92#define ERR_PTR_INTERNAL_2(n, d) ERR_PTR_INTERNAL_1(ERR(n, d))
93#define ERR_PTR_INTERNAL_1(e) ((void *) (e))
94#define ERR_PTR(...) PP_CALL(ERR_PTR_INTERNAL, __VA_ARGS__)
95
96#define ERR_FACILITY(n) __err_facility_##n
97#define ERR_FACILITY_EXTERN(n) extern struct err_facility __err_facility_##n
98#define ERR_FACILITY_DEFINE(n, ...) \
99 LINKER_SECTION_OBJECT(struct err_facility, err_facilities) \
100 __err_facility_##n = {.name = #n, __VA_ARGS__}
101
102/* Used as a return value to reduce signature length noise */
103#define err_checked enum err cc_warn_unused_result
104
105LINKER_SECTION_EXTERN(struct err_facility, err_facilities);
106
107const char *err_facility_to_str(enum err err);
108void err_facilities_init(void);
109
110STRINGIFY_DECLARE(errno_to_str, enum err) {
111 switch (stringify_in) {
112 case ERR_OK: return "No error";
113 case ERR_UNKNOWN: return "Unknown error";
114 case ERR_NO_MEM: return "Out of memory";
115 case ERR_NO_DEV: return "No such device";
116 case ERR_NO_ENT: return "No such file or directory";
117 case ERR_EXIST: return "File already exists";
118 case ERR_IO: return "I/O error";
119 case ERR_NOT_DIR: return "Not a directory";
120 case ERR_IS_DIR: return "Is a directory";
121 case ERR_INVAL: return "Invalid argument";
122 case ERR_PERM: return "Permission denied";
123 case ERR_FAULT: return "Bad memory access";
124 case ERR_BUSY: return "Resource busy";
125 case ERR_AGAIN: return "Try again";
126 case ERR_NOT_IMPL: return "Not implemented";
127 case ERR_NOSPC: return "No space left";
128 case ERR_OVERFLOW: return "Value too large";
129 case ERR_NOT_EMPTY: return "Directory not empty";
130
131 default: return err_facility_to_str(err: stringify_in);
132 }
133}
134