The Pedigree Project 0.1
AcpiS5.h
1/* Copyright (c) 2026, Pedigree Developers. */
2#ifndef PEDIGREE_MACHINE_PC_ACPI_S5_H
3#define PEDIGREE_MACHINE_PC_ACPI_S5_H
4
5#include <stddef.h>
6#include <stdint.h>
7
8// This deliberately accepts only static namespace declarations. Executable AML
9// and firmware sleep methods require an interpreter before they can be used.
10namespace AcpiS5 {
11inline bool mayHaveSleepHooks(const uint8_t* bytes, size_t length) {
12 // False positives in strings or nested objects are acceptable: without an
13 // interpreter we must not silently skip firmware's orderly S5 preparation.
14 for (size_t i = 0; i + 4 <= length; ++i) {
15 if (bytes[i] == '_' && bytes[i + 2] == 'T' && bytes[i + 3] == 'S' &&
16 (bytes[i + 1] == 'P' || bytes[i + 1] == 'T' || bytes[i + 1] == 'G'))
17 return true;
18 }
19 return false;
20}
21
22inline bool package(const uint8_t*& cursor, const uint8_t* end, const uint8_t*& packageEnd) {
23 if (cursor == end)
24 return false;
25 const uint8_t* start = cursor;
26 const uint8_t lead = *cursor++;
27 const unsigned extra = lead >> 6;
28 if (size_t(end - cursor) < extra || (extra && (lead & 0x30)))
29 return false;
30 size_t length = lead & (extra ? 0x0f : 0x3f);
31 for (unsigned i = 0; i < extra; ++i)
32 length |= size_t(*cursor++) << (4 + 8 * i);
33 if (length < size_t(cursor - start) || length > size_t(end - start))
34 return false;
35 packageEnd = start + length;
36 return true;
37}
38
39inline bool integer(const uint8_t*& cursor, const uint8_t* end, uint64_t& value) {
40 if (cursor == end)
41 return false;
42 const uint8_t op = *cursor++;
43 if (op == 0 || op == 1 || op == 0xff) {
44 value = op == 0xff ? UINT64_MAX : op;
45 return true;
46 }
47 const unsigned bytes = op == 0x0a ? 1 : op == 0x0b ? 2 : op == 0x0c ? 4 : op == 0x0e ? 8 : 0;
48 if (!bytes || size_t(end - cursor) < bytes)
49 return false;
50 value = 0;
51 for (unsigned i = 0; i < bytes; ++i)
52 value |= uint64_t(*cursor++) << (8 * i);
53 return true;
54}
55
56struct Name {
57 bool root;
58 bool s5;
59 bool rootScope;
60};
61
62inline bool name(const uint8_t*& cursor, const uint8_t* end, bool atRoot, Name& result) {
63 if (cursor == end)
64 return false;
65 bool root = atRoot;
66 if (*cursor == '\\') {
67 root = true;
68 ++cursor;
69 }
70 while (cursor != end && *cursor == '^') {
71 root = false;
72 ++cursor;
73 }
74 if (cursor == end)
75 return false;
76 unsigned count = 1;
77 if (*cursor == 0) {
78 count = 0;
79 ++cursor;
80 } else if (*cursor == 0x2e) {
81 count = 2;
82 ++cursor;
83 } else if (*cursor == 0x2f) {
84 if (++cursor == end)
85 return false;
86 count = *cursor++;
87 if (!count)
88 return false;
89 }
90 if (size_t(end - cursor) < count * 4)
91 return false;
92 result = {root,
93 root && count == 1 && cursor[0] == '_' && cursor[1] == 'S' && cursor[2] == '5' &&
94 cursor[3] == '_',
95 root && count == 0};
96 for (unsigned i = 0; i < count * 4; ++i) {
97 const uint8_t c = *cursor++;
98 if (c != '_' && !(c >= 'A' && c <= 'Z') && !(i % 4 && c >= '0' && c <= '9'))
99 return false;
100 }
101 return true;
102}
103
104inline bool data(const uint8_t*& cursor, const uint8_t* end) {
105 if (cursor == end)
106 return false;
107 const uint8_t op = *cursor;
108 if (op == 0x11 || op == 0x12 || op == 0x13) {
109 ++cursor;
110 const uint8_t* packageEnd;
111 if (!package(cursor, end, packageEnd))
112 return false;
113 cursor = packageEnd;
114 return true;
115 }
116 if (op == 0x0d) {
117 while (++cursor != end)
118 if (*cursor == 0) {
119 ++cursor;
120 return true;
121 }
122 return false;
123 }
124 if (op == 0 || op == 1 || op == 0xff || op == 0x0a || op == 0x0b || op == 0x0c || op == 0x0e) {
125 uint64_t value;
126 return integer(cursor, end, value);
127 }
128 Name ignored;
129 return name(cursor, end, false, ignored);
130}
131
132inline bool find(const uint8_t* cursor, const uint8_t* end, uint8_t& typeA, uint8_t& typeB,
133 bool atRoot = true, unsigned depth = 0) {
134 if (depth > 16)
135 return false;
136 while (cursor != end) {
137 const uint8_t op = *cursor++;
138 Name object;
139 if (op == 0x08) {
140 if (!name(cursor, end, atRoot, object) || cursor == end)
141 return false;
142 if (object.s5 && *cursor == 0x12) {
143 ++cursor;
144 const uint8_t* packageEnd;
145 if (!package(cursor, end, packageEnd) || cursor == packageEnd)
146 return false;
147 const unsigned count = *cursor++;
148 uint64_t a, b;
149 if (count < 2 || !integer(cursor, packageEnd, a) || !integer(cursor, packageEnd, b) ||
150 a > 7 || b > 7)
151 return false;
152 for (unsigned i = 2; i < count; ++i) {
153 uint64_t reserved;
154 if (!integer(cursor, packageEnd, reserved))
155 return false;
156 }
157 if (cursor != packageEnd)
158 return false;
159 typeA = a;
160 typeB = b;
161 return true;
162 }
163 if (!data(cursor, end))
164 return false;
165 } else if (op == 0x10 || op == 0x14 || op == 0xa0 || op == 0xa1 || op == 0xa2) {
166 const uint8_t* packageEnd;
167 if (!package(cursor, end, packageEnd))
168 return false;
169 if (op == 0x10) {
170 if (!name(cursor, packageEnd, atRoot, object))
171 return false;
172 if (find(cursor, packageEnd, typeA, typeB, object.rootScope, depth + 1))
173 return true;
174 }
175 cursor = packageEnd;
176 } else if (op == 0x06) {
177 if (!name(cursor, end, atRoot, object) || !name(cursor, end, atRoot, object))
178 return false;
179 } else if (op == 0x15) {
180 if (!name(cursor, end, atRoot, object) || end - cursor < 2)
181 return false;
182 cursor += 2;
183 } else if (op == 0x5b) {
184 if (cursor == end)
185 return false;
186 const uint8_t ext = *cursor++;
187 if (ext >= 0x81 && ext <= 0x87) {
188 const uint8_t* packageEnd;
189 if (!package(cursor, end, packageEnd))
190 return false;
191 cursor = packageEnd;
192 } else if (ext == 0x80 || ext == 0x01 || ext == 0x02) {
193 if (!name(cursor, end, atRoot, object))
194 return false;
195 if (ext != 0x02) {
196 if (cursor == end)
197 return false;
198 ++cursor;
199 }
200 if (ext == 0x80 && (!data(cursor, end) || !data(cursor, end)))
201 return false;
202 } else {
203 return false;
204 }
205 } else if (op != 0xa3) {
206 return false;
207 }
208 }
209 return false;
210}
211} // namespace AcpiS5
212#endif