summaryrefslogtreecommitdiff
path: root/lib/uefi.c3l/src/err.c3
blob: d21729b8d2d0a0b4f80ef2e8d9895948f67fbf9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* EFI errors can actually be faults: they should raise exceptions
	in the handling of a program, if the user so chooses to. */
module uefi::efi_error;
faultdef
	NO_FAULT,
	LOAD_ERROR,
	INVALID_PARAMETER,
	UNSUPPORTED,
	BAD_BUFFER_SIZE,
	BUFFER_TOO_SMALL,
	NOT_READY,
	DEVICE_ERROR,
	WRITE_PROTECTED,
	OUT_OF_RESOURCES,
	VOLUME_CORRUPTED,
	VOLUME_FULL,
	NO_MEDIA,
	MEDIA_CHANGED,
	NOT_FOUND,
	ACCESS_DENIED,
	NO_RESPONSE,
	NO_MAPPING,
	TIMEOUT,
	NOT_STARTED,
	ALREADY_STARTED,
	ABORTED,
	ICMP_ERROR,
	TFTP_ERROR,
	PROTOCOL_ERROR,
	INCOMPATIBLE_VERSION,
	SECURITY_VIOLATION,
	CRC_ERROR,
	END_OF_MEDIA,
	UNKNOWN_29, // NOTE: UEFI spec is missing this definition.
	UNKNOWN_30, // NOTE: UEFI spec is missing this definition.
	END_OF_FILE,
	INVALID_LANGUAGE,
	COMPROMISED_DATA,
	IP_ADDRESS_CONFLICT,
	HTTP_ERROR,
	EFILIB_UNINITIALIZED, // Used for efilib calls when init() hasn't been called.
	UNKNOWN_STATUS; /* Fallback for an unknown status code. */

module uefi::efi_warning;
faultdef
	UNKNOWN_GLYPH, DELETE_FAILURE, WRITE_FAILURE, BUFFER_TOO_SMALL, STALE_DATA, FILE_SYSTEM, RESET_REQUIRED;


module uefi;

import uefi::efi_error;
import uefi::efi_warning;

/** EFI_STATUS enum (apx D of the UEFI 2.11 specification). */
macro @efi_err($x) @private => (usz)((1l << ((usz::size * 8) - 1)) | $x);
macro @efi_warn($x) @private => (usz)$x;

enum EfiStatus : usz (usz raw, fault fault_type)
{
	SUCCESS { 0, efi_error::NO_FAULT },

	LOAD_ERROR           { @efi_err(1), efi_error::LOAD_ERROR },
	INVALID_PARAMETER    { @efi_err(2), efi_error::INVALID_PARAMETER },
	UNSUPPORTED          { @efi_err(3), efi_error::UNSUPPORTED },
	BAD_BUFFER_SIZE      { @efi_err(4), efi_error::BAD_BUFFER_SIZE },
	BUFFER_TOO_SMALL     { @efi_err(5), efi_error::BUFFER_TOO_SMALL },
	NOT_READY            { @efi_err(6), efi_error::NOT_READY },
	DEVICE_ERROR         { @efi_err(7), efi_error::DEVICE_ERROR },
	WRITE_PROTECTED      { @efi_err(8), efi_error::WRITE_PROTECTED },
	OUT_OF_RESOURCES     { @efi_err(9), efi_error::OUT_OF_RESOURCES },
	VOLUME_CORRUPTED     { @efi_err(10), efi_error::VOLUME_CORRUPTED },
	VOLUME_FULL          { @efi_err(11), efi_error::VOLUME_FULL },
	NO_MEDIA             { @efi_err(12), efi_error::NO_MEDIA },
	MEDIA_CHANGED        { @efi_err(13), efi_error::MEDIA_CHANGED },
	NOT_FOUND            { @efi_err(14), efi_error::NOT_FOUND },
	ACCESS_DENIED        { @efi_err(15), efi_error::ACCESS_DENIED },
	NO_RESPONSE          { @efi_err(16), efi_error::NO_RESPONSE },
	NO_MAPPING           { @efi_err(17), efi_error::NO_MAPPING },
	TIMEOUT              { @efi_err(18), efi_error::TIMEOUT },
	NOT_STARTED          { @efi_err(19), efi_error::NOT_STARTED },
	ALREADY_STARTED      { @efi_err(20), efi_error::ALREADY_STARTED },
	ABORTED              { @efi_err(21), efi_error::ABORTED },
	ICMP_ERROR           { @efi_err(22), efi_error::ICMP_ERROR },
	TFTP_ERROR           { @efi_err(23), efi_error::TFTP_ERROR },
	PROTOCOL_ERROR       { @efi_err(24), efi_error::PROTOCOL_ERROR },
	INCOMPATIBLE_VERSION { @efi_err(25), efi_error::INCOMPATIBLE_VERSION },
	SECURITY_VIOLATION   { @efi_err(26), efi_error::SECURITY_VIOLATION },
	CRC_ERROR            { @efi_err(27), efi_error::CRC_ERROR },
	END_OF_MEDIA         { @efi_err(28), efi_error::END_OF_MEDIA },
	UNKNOWN_29           { @efi_err(29), efi_error::UNKNOWN_29 }, /* NOTE: UEFI spec is missing this definition. */
	UNKNOWN_30           { @efi_err(30), efi_error::UNKNOWN_30 }, /* NOTE: UEFI spec is missing this definition. */
	END_OF_FILE          { @efi_err(31), efi_error::END_OF_FILE },
	INVALID_LANGUAGE     { @efi_err(32), efi_error::INVALID_LANGUAGE },
	COMPROMISED_DATA     { @efi_err(33), efi_error::COMPROMISED_DATA },
	IP_ADDRESS_CONFLICT  { @efi_err(34), efi_error::IP_ADDRESS_CONFLICT },
	HTTP_ERROR           { @efi_err(35), efi_error::HTTP_ERROR },

	WARN_UNKNOWN_GLYPH    { @efi_warn(1), efi_warning::UNKNOWN_GLYPH },
	WARN_DELETE_FAILURE   { @efi_warn(2), efi_warning::DELETE_FAILURE },
	WARN_WRITE_FAILURE    { @efi_warn(3), efi_warning::WRITE_FAILURE },
	WARN_BUFFER_TOO_SMALL { @efi_warn(4), efi_warning::BUFFER_TOO_SMALL },
	WARN_STALE_DATA       { @efi_warn(5), efi_warning::STALE_DATA },
	WARN_FILE_SYSTEM      { @efi_warn(6), efi_warning::FILE_SYSTEM },
	WARN_RESET_REQUIRED   { @efi_warn(7), efi_warning::RESET_REQUIRED },
}


// //////////////////////////////////////////////////////////////////////
<*
 Handle EFI errors when they occur.
 @param status : `The EfiStatus code to check`
 @param throw_on_warnings : `Return a ``true`` value on EFI_WARN_... codes`
 @return ```false`` on success. ``true`` when ``throw_on_warnings`` is false and ``status`` is a warning. Returns a fault otherwise.`
*>
fn bool? efi_error(EfiStatus status, bool throw_on_warnings = true) @export("efi_error") @builtin
{
	switch
	{
		case status == SUCCESS: return false;

		case status >= EfiStatus.WARN_UNKNOWN_GLYPH && status <= EfiStatus.WARN_RESET_REQUIRED:
			return throw_on_warnings ? status.fault_type~ : true;

		case status >= EfiStatus.LOAD_ERROR && status <= EfiStatus.HTTP_ERROR:
			return status.fault_type~;
	}

	return efi_error::UNKNOWN_STATUS~;
}