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