1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 UINT64
ticks_read(VOID
) {
11 __asm__
volatile ("rdtsc" : "=a" (a
), "=d" (d
));
14 #elif defined(__i386__)
15 UINT64
ticks_read(VOID
) {
17 __asm__
volatile ("rdtsc" : "=A" (val
));
21 UINT64
ticks_read(VOID
) {
27 /* count TSC ticks during a millisecond delay */
28 UINT64
ticks_freq(VOID
) {
29 UINT64 ticks_start
, ticks_end
;
31 ticks_start
= ticks_read();
32 uefi_call_wrapper(BS
->Stall
, 1, 1000);
33 ticks_end
= ticks_read();
35 return (ticks_end
- ticks_start
) * 1000UL;
38 UINT64
time_usec(VOID
) {
52 return 1000UL * 1000UL * ticks
/ freq
;
55 EFI_STATUS
parse_boolean(const CHAR8
*v
, BOOLEAN
*b
) {
57 return EFI_INVALID_PARAMETER
;
59 if (strcmpa(v
, (CHAR8
*)"1") == 0 ||
60 strcmpa(v
, (CHAR8
*)"yes") == 0 ||
61 strcmpa(v
, (CHAR8
*)"y") == 0 ||
62 strcmpa(v
, (CHAR8
*)"true") == 0) {
67 if (strcmpa(v
, (CHAR8
*)"0") == 0 ||
68 strcmpa(v
, (CHAR8
*)"no") == 0 ||
69 strcmpa(v
, (CHAR8
*)"n") == 0 ||
70 strcmpa(v
, (CHAR8
*)"false") == 0) {
75 return EFI_INVALID_PARAMETER
;
78 EFI_STATUS
efivar_set_raw(const EFI_GUID
*vendor
, const CHAR16
*name
, const VOID
*buf
, UINTN size
, UINT32 flags
) {
79 flags
|= EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
80 return uefi_call_wrapper(RT
->SetVariable
, 5, (CHAR16
*) name
, (EFI_GUID
*)vendor
, flags
, size
, (VOID
*) buf
);
83 EFI_STATUS
efivar_set(const EFI_GUID
*vendor
, const CHAR16
*name
, const CHAR16
*value
, UINT32 flags
) {
84 return efivar_set_raw(vendor
, name
, value
, value
? (StrLen(value
) + 1) * sizeof(CHAR16
) : 0, flags
);
87 EFI_STATUS
efivar_set_uint_string(const EFI_GUID
*vendor
, CHAR16
*name
, UINTN i
, UINT32 flags
) {
90 SPrint(str
, 32, L
"%u", i
);
91 return efivar_set(vendor
, name
, str
, flags
);
94 EFI_STATUS
efivar_set_uint32_le(const EFI_GUID
*vendor
, CHAR16
*name
, UINT32 value
, UINT32 flags
) {
97 buf
[0] = (UINT8
)(value
>> 0U & 0xFF);
98 buf
[1] = (UINT8
)(value
>> 8U & 0xFF);
99 buf
[2] = (UINT8
)(value
>> 16U & 0xFF);
100 buf
[3] = (UINT8
)(value
>> 24U & 0xFF);
102 return efivar_set_raw(vendor
, name
, buf
, sizeof(buf
), flags
);
105 EFI_STATUS
efivar_set_uint64_le(const EFI_GUID
*vendor
, CHAR16
*name
, UINT64 value
, UINT32 flags
) {
108 buf
[0] = (UINT8
)(value
>> 0U & 0xFF);
109 buf
[1] = (UINT8
)(value
>> 8U & 0xFF);
110 buf
[2] = (UINT8
)(value
>> 16U & 0xFF);
111 buf
[3] = (UINT8
)(value
>> 24U & 0xFF);
112 buf
[4] = (UINT8
)(value
>> 32U & 0xFF);
113 buf
[5] = (UINT8
)(value
>> 40U & 0xFF);
114 buf
[6] = (UINT8
)(value
>> 48U & 0xFF);
115 buf
[7] = (UINT8
)(value
>> 56U & 0xFF);
117 return efivar_set_raw(vendor
, name
, buf
, sizeof(buf
), flags
);
120 EFI_STATUS
efivar_get(const EFI_GUID
*vendor
, const CHAR16
*name
, CHAR16
**value
) {
121 _cleanup_freepool_ CHAR8
*buf
= NULL
;
126 err
= efivar_get_raw(vendor
, name
, &buf
, &size
);
130 /* Make sure there are no incomplete characters in the buffer */
132 return EFI_INVALID_PARAMETER
;
137 /* Return buffer directly if it happens to be NUL terminated already */
138 if (size
>= 2 && buf
[size
-2] == 0 && buf
[size
-1] == 0) {
139 *value
= (CHAR16
*) TAKE_PTR(buf
);
143 /* Make sure a terminating NUL is available at the end */
144 val
= AllocatePool(size
+ 2);
146 return EFI_OUT_OF_RESOURCES
;
148 CopyMem(val
, buf
, size
);
149 val
[size
/2] = 0; /* NUL terminate */
155 EFI_STATUS
efivar_get_uint_string(const EFI_GUID
*vendor
, const CHAR16
*name
, UINTN
*i
) {
156 _cleanup_freepool_ CHAR16
*val
= NULL
;
159 err
= efivar_get(vendor
, name
, &val
);
160 if (!EFI_ERROR(err
) && i
)
166 EFI_STATUS
efivar_get_uint32_le(const EFI_GUID
*vendor
, const CHAR16
*name
, UINT32
*ret
) {
167 _cleanup_freepool_ CHAR8
*buf
= NULL
;
171 err
= efivar_get_raw(vendor
, name
, &buf
, &size
);
172 if (!EFI_ERROR(err
) && ret
) {
173 if (size
!= sizeof(UINT32
))
174 return EFI_BUFFER_TOO_SMALL
;
176 *ret
= (UINT32
) buf
[0] << 0U | (UINT32
) buf
[1] << 8U | (UINT32
) buf
[2] << 16U |
177 (UINT32
) buf
[3] << 24U;
183 EFI_STATUS
efivar_get_uint64_le(const EFI_GUID
*vendor
, const CHAR16
*name
, UINT64
*ret
) {
184 _cleanup_freepool_ CHAR8
*buf
= NULL
;
188 err
= efivar_get_raw(vendor
, name
, &buf
, &size
);
189 if (!EFI_ERROR(err
) && ret
) {
190 if (size
!= sizeof(UINT64
))
191 return EFI_BUFFER_TOO_SMALL
;
193 *ret
= (UINT64
) buf
[0] << 0U | (UINT64
) buf
[1] << 8U | (UINT64
) buf
[2] << 16U |
194 (UINT64
) buf
[3] << 24U | (UINT64
) buf
[4] << 32U | (UINT64
) buf
[5] << 40U |
195 (UINT64
) buf
[6] << 48U | (UINT64
) buf
[7] << 56U;
201 EFI_STATUS
efivar_get_raw(const EFI_GUID
*vendor
, const CHAR16
*name
, CHAR8
**buffer
, UINTN
*size
) {
202 _cleanup_freepool_ CHAR8
*buf
= NULL
;
206 l
= sizeof(CHAR16
*) * EFI_MAXIMUM_VARIABLE_SIZE
;
207 buf
= AllocatePool(l
);
209 return EFI_OUT_OF_RESOURCES
;
211 err
= uefi_call_wrapper(RT
->GetVariable
, 5, (CHAR16
*) name
, (EFI_GUID
*)vendor
, NULL
, &l
, buf
);
212 if (!EFI_ERROR(err
)) {
215 *buffer
= TAKE_PTR(buf
);
224 EFI_STATUS
efivar_get_boolean_u8(const EFI_GUID
*vendor
, const CHAR16
*name
, BOOLEAN
*ret
) {
225 _cleanup_freepool_ CHAR8
*b
= NULL
;
229 err
= efivar_get_raw(vendor
, name
, &b
, &size
);
236 VOID
efivar_set_time_usec(const EFI_GUID
*vendor
, CHAR16
*name
, UINT64 usec
) {
244 SPrint(str
, 32, L
"%ld", usec
);
245 efivar_set(vendor
, name
, str
, 0);
248 static INTN
utf8_to_16(CHAR8
*stra
, CHAR16
*c
) {
252 if (!(stra
[0] & 0x80))
254 else if ((stra
[0] & 0xe0) == 0xc0)
256 else if ((stra
[0] & 0xf0) == 0xe0)
258 else if ((stra
[0] & 0xf8) == 0xf0)
260 else if ((stra
[0] & 0xfc) == 0xf8)
262 else if ((stra
[0] & 0xfe) == 0xfc)
272 unichar
= stra
[0] & 0x1f;
275 unichar
= stra
[0] & 0x0f;
278 unichar
= stra
[0] & 0x07;
281 unichar
= stra
[0] & 0x03;
284 unichar
= stra
[0] & 0x01;
288 for (UINTN i
= 1; i
< len
; i
++) {
289 if ((stra
[i
] & 0xc0) != 0x80)
292 unichar
|= stra
[i
] & 0x3f;
299 CHAR16
*stra_to_str(CHAR8
*stra
) {
306 str
= AllocatePool((len
+ 1) * sizeof(CHAR16
));
313 utf8len
= utf8_to_16(stra
+ i
, str
+ strlen
);
315 /* invalid utf8 sequence, skip the garbage */
327 CHAR16
*stra_to_path(CHAR8
*stra
) {
334 str
= AllocatePool((len
+ 2) * sizeof(CHAR16
));
342 utf8len
= utf8_to_16(stra
+ i
, str
+ strlen
);
344 /* invalid utf8 sequence, skip the garbage */
349 if (str
[strlen
] == '/')
351 if (str
[strlen
] == '\\' && str
[strlen
-1] == '\\') {
352 /* skip double slashes */
364 CHAR8
*strchra(CHAR8
*s
, CHAR8 c
) {
372 const CHAR16
*startswith(const CHAR16
*s
, const CHAR16
*prefix
) {
376 if (StrnCmp(s
, prefix
, l
) == 0)
382 const CHAR16
*endswith(const CHAR16
*s
, const CHAR16
*postfix
) {
386 pl
= StrLen(postfix
);
394 if (StrnCmp(s
+ sl
- pl
, postfix
, pl
) != 0)
400 const CHAR16
*startswith_no_case(const CHAR16
*s
, const CHAR16
*prefix
) {
404 if (StriCmp(s
, prefix
) == 0)
410 const CHAR16
*endswith_no_case(const CHAR16
*s
, const CHAR16
*postfix
) {
414 pl
= StrLen(postfix
);
422 if (StriCmp(s
+ sl
- pl
, postfix
) != 0)
428 EFI_STATUS
file_read(EFI_FILE_HANDLE dir
, const CHAR16
*name
, UINTN off
, UINTN size
, CHAR8
**ret
, UINTN
*ret_size
) {
429 _cleanup_(FileHandleClosep
) EFI_FILE_HANDLE handle
= NULL
;
430 _cleanup_freepool_ CHAR8
*buf
= NULL
;
433 err
= uefi_call_wrapper(dir
->Open
, 5, dir
, &handle
, (CHAR16
*) name
, EFI_FILE_MODE_READ
, 0ULL);
438 _cleanup_freepool_ EFI_FILE_INFO
*info
;
440 info
= LibFileInfo(handle
);
442 return EFI_OUT_OF_RESOURCES
;
444 size
= info
->FileSize
+1;
448 err
= uefi_call_wrapper(handle
->SetPosition
, 2, handle
, off
);
453 buf
= AllocatePool(size
+ 1);
455 return EFI_OUT_OF_RESOURCES
;
457 err
= uefi_call_wrapper(handle
->Read
, 3, handle
, &size
, buf
);
463 *ret
= TAKE_PTR(buf
);
470 EFI_STATUS
log_oom(void) {
471 Print(L
"Out of memory.");
472 (void) uefi_call_wrapper(BS
->Stall
, 1, 3 * 1000 * 1000);
473 return EFI_OUT_OF_RESOURCES
;