getenv, setenv plus initial AArch64 support (works with LLVM)

This commit is contained in:
bzt 2021-02-02 23:00:56 +01:00
parent 13c9ef2031
commit 495cceb264
7 changed files with 384 additions and 62 deletions

View file

@ -68,7 +68,7 @@ is given, then LLVM CLang + lld used, and native PE is generated, no conversion
| `LDFLAGS` | linker flags you want to use (I don't think you'll ever need this, just in case) | | `LDFLAGS` | linker flags you want to use (I don't think you'll ever need this, just in case) |
| `LIBS` | additional libraries you want to link with (like "-lm", only static .a libraries allowed) | | `LIBS` | additional libraries you want to link with (like "-lm", only static .a libraries allowed) |
| `USE_LLVM` | set this if you want LLVM Clang + Lld instead of GNU gcc + ld | | `USE_LLVM` | set this if you want LLVM Clang + Lld instead of GNU gcc + ld |
| `ARCH` | the target architecture (only x86_64 supported for now, but the toolchain can handle multiple archs) | | `ARCH` | the target architecture |
Here's a more advanced **Makefile** example: Here's a more advanced **Makefile** example:
``` ```
@ -82,6 +82,9 @@ LIBS = -lm
USE_LLVM = 1 USE_LLVM = 1
include uefi/Makefile include uefi/Makefile
``` ```
The build environment configurator was created in a way that it can handle any number of architectures, however
there's only `x86_64` crt0 implemented for now. There's an experimental `aarch64` crt0, which only compiles with
the LLVM toolchain, GNU ld has some issues with it, saying "unsupported relocation" for ImageBase.
Notable Differences to POSIX libc Notable Differences to POSIX libc
--------------------------------- ---------------------------------
@ -94,12 +97,13 @@ All strings in the UEFI environment are stored with 16 bits wide characters. The
so for example your main() is NOT like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All so for example your main() is NOT like `main(int argc, char **argv)`, but `main(int argc, wchar_t **argv)` instead. All
the other string related libc functions (like strlen() for example) use this wide character type too. For this reason, you the other string related libc functions (like strlen() for example) use this wide character type too. For this reason, you
must specify your string literals with `L""` and characters with `L''`. Functions that supposed to handle characters in int must specify your string literals with `L""` and characters with `L''`. Functions that supposed to handle characters in int
type (like `getchar`, `putchar`), do not truncate to unsigned char, rather to wchar_t. There's an additional `getchar_ifany` type (like `getchar`, `putchar`), do not truncate to unsigned char, rather to wchar_t.
function, which does not block, but returns 0 when there's no key pressed.
File types in dirent are limited to directories and files only (DT_DIR, DT_REG), but for stat in addition to S_IFDIR and File types in dirent are limited to directories and files only (DT_DIR, DT_REG), but for stat in addition to S_IFDIR and
S_IFREG, S_IFIFO also returned (for console streams: stdin, stdout, stderr). S_IFREG, S_IFIFO also returned (for console streams: stdin, stdout, stderr).
Note that `getenv` and `setenv` aren't POSIX standard, because UEFI environment variables are binary blobs.
That's about it, everything else is the same. That's about it, everything else is the same.
List of Provided POSIX Functions List of Provided POSIX Functions
@ -114,7 +118,7 @@ List of Provided POSIX Functions
| rewinddir | as usual | | rewinddir | as usual |
| closedir | as usual | | closedir | as usual |
Because UEFI has no concept of devices files nor of symlinks, only DT_DIR and DT_REG supported. Because UEFI has no concept of device files nor of symlinks, dirent fields are limited and only DT_DIR and DT_REG supported.
### stdlib.h ### stdlib.h
@ -135,13 +139,30 @@ Because UEFI has no concept of devices files nor of symlinks, only DT_DIR and DT
| mbstowcs | as usual (UTF-8 string to wchar_t string) | | mbstowcs | as usual (UTF-8 string to wchar_t string) |
| wcstombs | as usual (wchar_t string to UTF-8 string) | | wcstombs | as usual (wchar_t string to UTF-8 string) |
| srand | as usual | | srand | as usual |
| rand | as usual, uses EFI_RNG_PROTOCOL if possible | | rand | as usual, but uses EFI_RNG_PROTOCOL if possible |
| getenv | pretty UEFI specific |
| setenv | pretty UEFI specific |
```c
int exit_bs()
```
Exit Boot Services. Returns 0 on success.
```c
uint8_t *getenv(wchar_t *name, uintn_t *len);
```
Query the value of environment variable `name`. On success, `len` is set, and a malloc'd buffer returned. It is
the caller's responsibility to free the buffer later. On error returns NULL.
```c
int setenv(wchar_t *name, uintn_t len, uint8_t *data);
```
Sets an environment variable by `name` with `data` of length `len`. On success returns 1, otherwise 0 on error.
### stdio.h ### stdio.h
| Function | Description | | Function | Description |
|---------------|----------------------------------------------------------------------------| |---------------|----------------------------------------------------------------------------|
| fopen | as usual, but accepts wide char strings, for mode L"r", L"w" and L"a" only | | fopen | as usual, but accepts wide char strings, also for mode |
| fclose | as usual | | fclose | as usual |
| fflush | as usual | | fflush | as usual |
| fread | as usual, only real files accepted (no stdin) | | fread | as usual, only real files accepted (no stdin) |
@ -161,7 +182,7 @@ Because UEFI has no concept of devices files nor of symlinks, only DT_DIR and DT
| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise | | getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise |
| putchar | as usual, stdout only (no redirects) | | putchar | as usual, stdout only (no redirects) |
File open modes: `r` read, `w` write, `a` append. Because of UEFI peculiarities, `wd` creates directory. File open modes: `L"r"` read, `L"w"` write, `L"a"` append. Because of UEFI peculiarities, `L"wd"` creates directory.
String formating is limited; only supports padding via number prefixes, `%d`, `%x`, `%X`, `%c`, `%s`, `%q` and String formating is limited; only supports padding via number prefixes, `%d`, `%x`, `%X`, `%c`, `%s`, `%q` and
`%p`. Because it operates on wchar_t, it also supports the non-standard `%C` (printing an UTF-8 character, needs `%p`. Because it operates on wchar_t, it also supports the non-standard `%C` (printing an UTF-8 character, needs
@ -247,7 +268,7 @@ Calling UEFI functions is as simple as with EDK II, just do the call, no need fo
``` ```
There are two additional, non-POSIX calls in the library. One is `exit_bs()` to exit Boot Services, and the other is There are two additional, non-POSIX calls in the library. One is `exit_bs()` to exit Boot Services, and the other is
a non-blocking `getchar_ifany()`. a non-blocking version `getchar_ifany()`.
Unlike gnu-efi, POSIX-UEFI does not pollute your application's namespace with unused GUID variables. It only provides Unlike gnu-efi, POSIX-UEFI does not pollute your application's namespace with unused GUID variables. It only provides
header definitions, so you must create each GUID instance if and when you need them. header definitions, so you must create each GUID instance if and when you need them.
@ -267,3 +288,14 @@ naming conflicts. POSIX-UEFI itself ships the very minimum set of typedefs and s
#include <efi.h> #include <efi.h>
#include <uefi.h> /* this will work as expected! Both POSIX-UEFI and EDK II / gnu-efi typedefs available */ #include <uefi.h> /* this will work as expected! Both POSIX-UEFI and EDK II / gnu-efi typedefs available */
``` ```
The advantage of this is that you can use the simplicity of the POSIX-UEFI library and build environment, while getting
access to the most up-to-date protocol and interface definitions at the same time.
License
-------
POSIX_UEFI is licensed under the terms of the MIT license.
Cheers,
bzt

View file

@ -8,12 +8,14 @@ endif
SRCS ?= $(wildcard *.c) $(wildcard *.S) SRCS ?= $(wildcard *.c) $(wildcard *.S)
TMP = $(SRCS:.c=.o) TMP = $(SRCS:.c=.o)
OBJS = $(TMP:.S=.o) OBJS = $(TMP:.S=.o)
CFLAGS += -mno-red-zone -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check \ CFLAGS += -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -I. -I./uefi \
-D__$(ARCH)__ -DHAVE_USE_MS_ABI \ -I/usr/include -I/usr/include/efi -I/usr/include/efi/protocol -I/usr/include/efi/$(ARCH) -D__$(ARCH)__
-I/usr/include -I. -I./uefi -I/usr/include/efi -I/usr/include/efi/$(ARCH) -I/usr/include/efi/protocol ifeq ($(ARCH),x86_64)
CFLAGS += -DHAVE_USE_MS_ABI -mno-red-zone
endif
# for libuefi.a # for libuefi.a
LIBSRCS = $(filter-out crt_$(ARCH).c,$(wildcard *.c)) $(wildcard *.S) LIBSRCS = $(filter-out $(wildcard crt_*.c),$(wildcard *.c)) $(wildcard *.S)
TMP = $(LIBSRCS:.c=.o) TMP = $(LIBSRCS:.c=.o)
LIBOBJS = $(TMP:.S=.o) LIBOBJS = $(TMP:.S=.o)
@ -22,7 +24,10 @@ ifeq ($(wildcard /usr/bin/gcc),)
USE_LLVM = 1 USE_LLVM = 1
endif endif
ifeq ($(USE_LLVM),) ifeq ($(USE_LLVM),)
CFLAGS += -Wno-builtin-declaration-mismatch -fpic -maccumulate-outgoing-args ifeq ($(ARCH),x86_64)
CFLAGS += -maccumulate-outgoing-args
endif
CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC
LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o
LIBS += -o $(TARGET).so -luefi -T uefi/elf_$(ARCH)_efi.lds LIBS += -o $(TARGET).so -luefi -T uefi/elf_$(ARCH)_efi.lds
# see if we're cross-compiling # see if we're cross-compiling
@ -54,7 +59,7 @@ endif
all: $(ALLTARGETS) all: $(ALLTARGETS)
uefi/libuefi.a: uefi/libuefi.a:
make --no-print-directory -C uefi libuefi.a USE_LLVM=$(USE_LLVM) @make --no-print-directory -C uefi libuefi.a USE_LLVM=$(USE_LLVM) ARCH=$(ARCH)
libuefi.lib: $(LIBOBJS) libuefi.lib: $(LIBOBJS)

195
uefi/crt_aarch64.c Normal file
View file

@ -0,0 +1,195 @@
/*
* crt_aarch64.c
*
* Copyright (C) 2021 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* This file is part of the POSIX-UEFI package.
* @brief C runtime, bootstraps an EFI application to call standard main()
*
*/
#include <uefi.h>
/* this is implemented by the application */
extern int main(int argc, wchar_t **argv);
/* definitions for elf relocations */
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
typedef uint64_t Elf64_Addr;
typedef struct
{
Elf64_Sxword d_tag; /* Dynamic entry type */
union
{
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
} Elf64_Dyn;
#define DT_NULL 0 /* Marks end of dynamic section */
#define DT_RELA 7 /* Address of Rela relocs */
#define DT_RELASZ 8 /* Total size of Rela relocs */
#define DT_RELAENT 9 /* Size of one Rela reloc */
typedef struct
{
Elf64_Addr r_offset; /* Address */
Elf64_Xword r_info; /* Relocation type and symbol index */
} Elf64_Rel;
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define R_AARCH64_RELATIVE 1027 /* Adjust by program base */
/* globals to store system table pointers */
efi_handle_t IM = NULL;
efi_system_table_t *ST = NULL;
efi_boot_services_t *BS = NULL;
efi_runtime_services_t *RT = NULL;
efi_loaded_image_protocol_t *LIP = NULL;
/* we only need one .o file, so use inline Assembly here */
void bootstrap()
{
__asm__ __volatile__ (
/* call init in C */
" .align 4\n"
#ifndef __clang__
" .globl _start\n"
"_start:\n"
" adr x2, ImageBase\n"
/* " mov x2, xzr\n" */
" adrp x3, _DYNAMIC\n"
" add x3, x3, #:lo12:_DYNAMIC\n"
" bl uefi_init\n"
" ret\n"
/* fake a relocation record, so that EFI won't complain */
" .data\n"
"dummy: .long 0\n"
" .section .reloc, \"a\"\n"
"label1:\n"
" .long dummy-label1\n"
" .long 10\n"
" .word 0\n"
".text\n"
#else
" .globl __chkstk\n"
"__chkstk:\n"
" ret\n"
#endif
/* setjmp and longjmp */
" .p2align 3\n"
" .globl setjmp\n"
"setjmp:\n"
" mov x16, sp\n"
" stp x19, x20, [x0, #0]\n"
" stp x21, x22, [x0, #16]\n"
" stp x23, x24, [x0, #32]\n"
" stp x25, x26, [x0, #48]\n"
" stp x27, x28, [x0, #64]\n"
" stp x29, x30, [x0, #80]\n"
" str x16, [x0, #96]\n"
" stp d8, d9, [x0, #112]\n"
" stp d10, d11, [x0, #128]\n"
" stp d12, d13, [x0, #144]\n"
" stp d14, d15, [x0, #160]\n"
" mov w0, #0\n"
" ret\n"
" .globl longjmp\n"
"longjmp:\n"
" ldp x19, x20, [x0, #0]\n"
" ldp x21, x22, [x0, #16]\n"
" ldp x23, x24, [x0, #32]\n"
" ldp x25, x26, [x0, #48]\n"
" ldp x27, x28, [x0, #64]\n"
" ldp x29, x30, [x0, #80]\n"
" ldr x16, [x0, #96]\n"
" ldp d8, d9, [x0, #112]\n"
" ldp d10, d11, [x0, #128]\n"
" ldp d12, d13, [x0, #144]\n"
" ldp d14, d15, [x0, #160]\n"
" mov sp, x16\n"
" cmp w1, #0\n"
" mov w0, #1\n"
" csel w0, w1, w0, ne\n"
" br x30\n"
);
}
/**
* Initialize POSIX-UEFI and call the application's main() function
*/
int uefi_init (
efi_handle_t image, efi_system_table_t *systab
#ifndef __clang__
, uintptr_t ldbase, Elf64_Dyn *dyn
#endif
) {
efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
efi_shell_parameters_protocol_t *shp = NULL;
efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
efi_shell_interface_protocol_t *shi = NULL;
efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
efi_status_t status;
int argc = 0;
wchar_t **argv = NULL;
#ifndef __clang__
int i;
long relsz = 0, relent = 0;
Elf64_Rel *rel = 0;
uintptr_t *addr;
/* handle relocations */
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
switch (dyn[i].d_tag) {
case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
default: break;
}
}
if (rel && relent) {
while (relsz > 0) {
if(ELF64_R_TYPE (rel->r_info) == R_AARCH64_RELATIVE)
{ addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; break; }
rel = (Elf64_Rel*) ((char *) rel + relent);
relsz -= relent;
}
}
#endif
/* save EFI pointers and loaded image into globals */
IM = image;
ST = systab;
BS = systab->BootServices;
RT = systab->RuntimeServices;
BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
/* get command line arguments */
status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if(!EFI_ERROR(status) && shp) { argc = shp->Argc; argv = shp->Argv; }
else {
/* if shell 2.0 failed, fallback to shell 1.0 interface */
status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if(!EFI_ERROR(status) && shi) { argc = shi->Argc; argv = shi->Argv; }
}
/* call main */
return main(argc, argv);
}

View file

@ -70,59 +70,61 @@ void bootstrap()
{ {
__asm__ __volatile__ ( __asm__ __volatile__ (
/* call init in C */ /* call init in C */
" .align 4;" " .align 4\n"
#ifndef __clang__ #ifndef __clang__
" .globl _start;" " .globl _start\n"
"_start:" "_start:\n"
" lea ImageBase(%rip), %rdi;" " lea ImageBase(%rip), %rdi\n"
" lea _DYNAMIC(%rip), %rsi;" " lea _DYNAMIC(%rip), %rsi\n"
" call uefi_init;" " call uefi_init\n"
" ret;" " ret\n"
/* fake a relocation record, so that EFI won't complain */ /* fake a relocation record, so that EFI won't complain */
" .data;" " .data\n"
"dummy: .long 0;" "dummy: .long 0\n"
" .section .reloc, \"a\";" " .section .reloc, \"a\"\n"
"label1:;" "label1:\n"
" .long dummy-label1;" " .long dummy-label1\n"
" .long 10;" " .long 10\n"
" .word 0;" " .word 0\n"
".text;" ".text\n"
#else #else
" .globl __chkstk;" " .globl __chkstk\n"
"__chkstk:" "__chkstk:\n"
" ret;" " ret\n"
#endif #endif
/* setjmp and longjmp */ /* setjmp and longjmp */
" .globl setjmp;" " .globl setjmp\n"
"setjmp:" "setjmp:\n"
" pop %rsi;" " pop %rsi\n"
" movq %rbx,0x00(%rdi);" " movq %rbx,0x00(%rdi)\n"
" movq %rsp,0x08(%rdi);" " movq %rsp,0x08(%rdi)\n"
" push %rsi;" " push %rsi\n"
" movq %rbp,0x10(%rdi);" " movq %rbp,0x10(%rdi)\n"
" movq %r12,0x18(%rdi);" " movq %r12,0x18(%rdi)\n"
" movq %r13,0x20(%rdi);" " movq %r13,0x20(%rdi)\n"
" movq %r14,0x28(%rdi);" " movq %r14,0x28(%rdi)\n"
" movq %r15,0x30(%rdi);" " movq %r15,0x30(%rdi)\n"
" movq %rsi,0x38(%rdi);" " movq %rsi,0x38(%rdi)\n"
" xor %rax,%rax;" " xor %rax,%rax\n"
" ret;" " ret\n"
" .globl longjmp;"
"longjmp:" " .globl longjmp\n"
" movl %esi, %eax;" "longjmp:\n"
" movq 0x00(%rdi), %rbx;" " movl %esi, %eax\n"
" movq 0x08(%rdi), %rsp;" " movq 0x00(%rdi), %rbx\n"
" movq 0x10(%rdi), %rbp;" " movq 0x08(%rdi), %rsp\n"
" movq 0x18(%rdi), %r12;" " movq 0x10(%rdi), %rbp\n"
" movq 0x20(%rdi), %r13;" " movq 0x18(%rdi), %r12\n"
" movq 0x28(%rdi), %r14;" " movq 0x20(%rdi), %r13\n"
" movq 0x30(%rdi), %r15;" " movq 0x28(%rdi), %r14\n"
" xor %rdx,%rdx;" " movq 0x30(%rdi), %r15\n"
" mov $1,%rcx;" " xor %rdx,%rdx\n"
" cmp %rax,%rdx;" " mov $1,%rcx\n"
" cmove %rcx,%rax;" " cmp %rax,%rdx\n"
" jmp *0x38(%rdi);" " cmove %rcx,%rax\n"
" jmp *0x38(%rdi)\n"
); );
} }

63
uefi/elf_aarch64_efi.lds Normal file
View file

@ -0,0 +1,63 @@
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SECTIONS
{
.text 0x0 : {
_text = .;
*(.text.head)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.srodata)
*(.rodata*)
. = ALIGN(16);
}
_etext = .;
_text_size = . - _text;
.dynamic : { *(.dynamic) }
.data : ALIGN(4096)
{
_data = .;
*(.sdata)
*(.data)
*(.data1)
*(.data.*)
*(.got.plt)
*(.got)
/* the EFI loader doesn't seem to like a .bss section, so we stick
it all into .data: */
. = ALIGN(16);
_bss = .;
*(.sbss)
*(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
. = ALIGN(16);
_bss_end = .;
}
.rela.dyn : { *(.rela.dyn) }
.rela.plt : { *(.rela.plt) }
.rela.got : { *(.rela.got) }
.rela.data : { *(.rela.data) *(.rela.data*) }
. = ALIGN(512);
_edata = .;
_data_size = . - _data;
. = ALIGN(4096);
.dynsym : { *(.dynsym) }
. = ALIGN(4096);
.dynstr : { *(.dynstr) }
. = ALIGN(4096);
.note.gnu.build-id : { *(.note.gnu.build-id) }
/DISCARD/ :
{
*(.rel.reloc)
*(.eh_frame)
*(.note.GNU-stack)
}
.comment 0 : { *(.comment) }
}

View file

@ -249,3 +249,25 @@ int rand()
ret ^= (int)(__srand_seed>>33); ret ^= (int)(__srand_seed>>33);
return ret; return ret;
} }
uint8_t *getenv(wchar_t *name, uintn_t *len)
{
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret;
uint32_t attr;
efi_status_t status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
*len = 0;
return NULL;
}
memcpy(ret, tmp, *len);
ret[*len] = 0;
return ret;
}
int setenv(wchar_t *name, uintn_t len, uint8_t *data)
{
efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
efi_status_t status = RT->SetVariable(name, &globGuid, 0, len, data);
return !EFI_ERROR(status);
}

View file

@ -213,6 +213,7 @@ typedef struct {
uint64_t FP; uint64_t FP;
uint64_t LR; uint64_t LR;
uint64_t IP0; uint64_t IP0;
uint64_t reserved;
uint64_t D8; uint64_t D8;
uint64_t D9; uint64_t D9;
uint64_t D10; uint64_t D10;
@ -608,7 +609,7 @@ typedef efi_status_t (EFIAPI *efi_set_wakeup_time_t)(boolean_t Enable, efi_time_
typedef efi_status_t (EFIAPI *efi_set_virtual_address_map_t)(uintn_t MemoryMapSize, uintn_t DescriptorSize, typedef efi_status_t (EFIAPI *efi_set_virtual_address_map_t)(uintn_t MemoryMapSize, uintn_t DescriptorSize,
uint32_t DescriptorVersion, efi_memory_descriptor_t *VirtualMap); uint32_t DescriptorVersion, efi_memory_descriptor_t *VirtualMap);
typedef efi_status_t (EFIAPI *efi_convert_pointer_t)(uintn_t DebugDisposition, void **Address); typedef efi_status_t (EFIAPI *efi_convert_pointer_t)(uintn_t DebugDisposition, void **Address);
typedef efi_status_t (EFIAPI *efi_get_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uintn_t *Attributes, typedef efi_status_t (EFIAPI *efi_get_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t *Attributes,
uintn_t *DataSize, void *Data); uintn_t *DataSize, void *Data);
typedef efi_status_t (EFIAPI *efi_get_next_variable_name_t)(uintn_t *VariableNameSize, wchar_t *VariableName, typedef efi_status_t (EFIAPI *efi_get_next_variable_name_t)(uintn_t *VariableNameSize, wchar_t *VariableName,
efi_guid_t *VendorGuid); efi_guid_t *VendorGuid);
@ -1246,6 +1247,8 @@ extern int getchar (void);
/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */ /* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */
extern int getchar_ifany (void); extern int getchar_ifany (void);
extern int putchar (int __c); extern int putchar (int __c);
extern uint8_t *getenv(wchar_t *name, uintn_t *len);
extern int setenv(wchar_t *name, uintn_t len, uint8_t *data);
/* string.h */ /* string.h */
#ifndef __clang__ #ifndef __clang__