diff --git a/libs/posix-uefi/LICENSE b/libs/posix-uefi/LICENSE new file mode 100644 index 0000000..f863cbc --- /dev/null +++ b/libs/posix-uefi/LICENSE @@ -0,0 +1,21 @@ + 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. diff --git a/libs/posix-uefi/OLVASSEL.md b/libs/posix-uefi/OLVASSEL.md new file mode 100644 index 0000000..c049658 --- /dev/null +++ b/libs/posix-uefi/OLVASSEL.md @@ -0,0 +1,385 @@ +POSIX-UEFI +========== + +
Hányunk attól az ocsmány UEFI API-tól, a megszokott POSIX-ot akarjuk!
+ +Ez egy nagyon minimális fordító környezet, ami segít UEFI-re fejleszteni Linux (vagy más POSIX kompatíbilis) rendszer alatt. +Nagy hatással volt rá a [gnu-efi](https://sourceforge.net/projects/gnu-efi) (minden elismerésem nekik), de annál kissebb, +egyszerűbb és könnyebben integrálható (működik LLVM Clang és GNU gcc környezettel is), valamint könnyebben is használható, +mivel POSIX-szerű API-t biztosít az UEFI alkalmazásod felé. + +Az UEFI környezet két komponensből áll: a GUID protokoll interfészű firmverből és egy felhasználói könyvtárból. Az előbbit +nem tudjuk lecserélni, de az utóbbit barátságosabbá tehetjük. És pont ez az, amit a POSIX-UEFI csinál. Egy vékony +függvénykönyvtár ami becsomagolja a GUID protokollos API-t, nem több, nem kevesebb, nem egy teljes értékű libc implementáció. + +Kétféleképp tudod integrálni a projektedbe: + +Statikus Függvénykönyvtárként +----------------------------- + +Azonos metódus, mint a gnu-efi-nél, nem igazán javasolt. Az `uefi` könyvtárban futtasd a következő parancsot +```sh +$ USE_GCC=1 make +``` +Ez létrehozza az `build/uefi` mappát, minden szükséges fájllal együtt. Ezek: + + - **crt0.o**, futásidejű kód, ami elind0tja a POSIX-UEFI-t + - **link.ld**, linkelő szkript, amit a POSIX-UEFI-vel használni kell (ugyanaz, mint gnu-efi esetén) + - **libuefi.a**, a függvénykönyvtár maga + - **uefi.h**, minden az egyben C / C++ fejlécfájl + +Ezzel összeszerkesztheted a programodat, de nem fogod tudni újrafordítani, és a linkeléssel és konvertálással is magadra +maradsz. + +Szigorúan véve csak a **crt0.o** és a **link.ld** fájlokra van szükség, ez elég ahhoz, hogy elindítsa és meghívja az alkalmazásod +"main()" eljárását. Viszont ahhoz, hogy a libc funkciókat (mint pl. memcmp, strcpy, malloc vagy fopen) használhasd, linkelned +kell a **libuefi.a** fájllal is. + +Egyenlőre ez a metódus csak gcc-vel működik, mivel a Clang úgy van beállítva, hogy direktben PE fájlokat hoz létre, ezért nem tud +statikus ELF .a fájlokat generálni, sem linkelni velük. + +Forrásként terjesztve +--------------------- + +Ez a javasolt mód, mivel ez biztosít egy Makefile-t is ami megfelelően beállítja a fordítókörnyezetedet. + + 1. másold be a `uefi` könyvtárat a forrásfádba (vagy állíts be egy git submodule-t és egy symlinket). Egy tucat fájl, kb. 132K összesen. + 2. csinálj egy hihetetlenül egyszerű **Makefile**-t, mint például az alábbi + 3. fordítsd le a programodat UEFI-re egy `make` hívással + +``` +TARGET = helloworld.efi +include uefi/Makefile +``` +Egy minta **helloworld.c** így néz ki: +```c +#include + +int main(int argc, char **argv) +{ + printf("Hello World!\n"); + return 0; +} +``` +Alapértelmezetten Clang + lld környezetet keres és állít be, ami direktben PE fájlt hoz létre konvertálás nélkül. Ha a `USE_GCC` +környezeti változó be van állítva, akkor a hoszt natív GNU gcc + ld használatával egy megosztott függvénykönyvtárat fordít, amit +aztán objcopy-val átkonvertál .efi fájllá, pont, mint ahogy a gnu-efi is csinálja. + +**MEGJEGYZÉS**: ha nem akarod az egész repót klónozni, csakis az `uefi` könyvtárat, akkor +``` +git clone --no-checkout https://gitlab.com/bztsrc/posix-uefi.git . +git sparse-checkout set --no-cone '/uefi/*' +git checkout +``` + +### Elérhető Makefile opciók + +| Változó | Leírás | +|------------|------------------------------------------------------------------------------------------------------| +| `TARGET` | a cél program (szükséges megadni) | +| `SRCS` | források listája, amiket fordítani kell (alapértelmezetten minden \*.c \*.S fájl) | +| `CFLAGS` | további fordító opciók (alapértelmezetten üres, pl. "-Wall -pedantic -std=c99") | +| `LDFLAGS` | további linkelő opciók (nem hiszem, hogy valaha is szükség lesz erre, csak a teljesség kedvéért) | +| `LIBS` | további függvénykönyvtárak, amikkel linkelni szeretnél (pl "-lm", csak statikus .a jöhet szóba) | +| `EXTRA` | bármi további obj fájl, amit még hozzá szeretnél linkelni | +| `ALSO` | további make szabályok futtatása | +| `OUTDIR` | ha meg van adva, akkor ide generálja a projekted obj fájljait (alapértelmezetten nincs beállítva) | +| `USE_GCC` | ha beállítod, akkor natív GNU gcc + ld + objcopy környzetet használ LLVM Clang + Lld helyett | +| `ARCH` | a cél architektúra | + +Itt van egy teljesebb **Makefile** példa: +``` +ARCH = x86_64 +TARGET = helloworld.efi +SRCS = $(wildcard *.c) +CFLAGS = -pedantic -Wall -Wextra -Werror --std=c11 -O2 +LDFLAGS = +LIBS = -lm +OUTDIR = build/loader + +USE_GCC = 1 +include uefi/Makefile +``` +A fordítási környezet konfiguráló úgy lett kialakítva, hogy akárhány architektúrával elboldogul, azonban eddig csak az +`x86_64` crt0 lett alaposan letesztelve. Van `aarch64` és `riscv64` crt0 is, de mivel nekem nincs sem ARM UEFI-s, sem +RISC-V UEFI-s gépem, **mindkettő teszteletlen**. Elvileg kéne működnie. Ha új architectúrára akarod portolni, akkor a +setjmp struct-ot kell megadni az uefi.h-ban, valamint csinálni neki egy crt0_X.c fájlt. Ennyi. Minden más +platformfüggetlenül lett megírva. + +### Elérhető konfigurációs opciók + +Ezeket az `uefi.h` elején lehet állítani. + +| Define | Leírás | +|-----------------------|-------------------------------------------------------------------------------------------| +| `UEFI_NO_UTF8` | Ne használjon transzparens UTF-8 konverziót az alkalmazás és az UEFI interfész között | +| `UEFI_NO_TRACK_ALLOC` | Ne tartsa nyilván a foglalt méreteket (gyorsabb, de bufferen kívülről olvas realloc-nál) | + +Lényeges eltérések a POSIX libc-től +----------------------------------- + +Ez a függvénykönyvtár korántsem annyira teljes, mint a glibc vagy a musl például. Csakis a legszükségesebb libc funkciókat +biztosítja, mivel egyszerűségre törekszik. A legjobb talán UEFI API burkolóként tekinteni rá, és nem pedig egy teljes POSIX +kompatíbilis libc-ként. + +UEFI alatt minden sztring 16 bit széles karakterekkel van tárolva. A függvénykönyvtár biztosít egy `wchar_t` típust ehhez, +és egy `UEFI_NO_UTF8` define opciót a transzparens `char` és `wchar_t` közötti konvertáláshoz. Ha megadod az `UEFI_NO_UTF8`-at, +akkor például a main() függvényed NEM `main(int argc, char **argv)` lesz, hanem `main(int argc, wchar_t **argv)`. Az összes +többi sztring függvény (mint például az strlen() is) ezt a széles karaktertípust fogja használni. Emiatt az összes sztring +konstansot `L""`-el, a karakterkonstansokat pedig `L''`-el kell definiálni. Hogy mindkét konfigurációt kezelni lehessen, +adott egy `char_t` típus, ami vagy `char` vagy `wchar_t`, és a `CL()` makró, ami `L` előtagot ad a konstansokhoz, amikor kell. +Azok a funkciók, amik a karaktereket int típusként kezelik (pl. `getchar`, `putchar`), nem unsigned char-ra csonkítanak, hanem +wchar_t-re. + +Sajnos az UEFI-ben nincs olyan, hogy buffer átméretezés. Az AllocatePool nem fogad bemenetet, és nincs mód egymár allokált +buffer méretének lekérésére sem. Szóval két rossz közül válaszhatunk a `realloc`-nál: +1. magunk tartjuk nyilván a méreteket, ami bonyolultabb kódot és lassabb futást jelent. +2. megbékélünk vele, hogy az adatok másolása az új bufferbe elkerülhetetlenül a régi bufferen túli olvasást eredményez. +Ez utőbbi opció választható az `UEFI_NO_TRACK_ALLOC` define megadásával. + +A fájl típusok a dirent-ben nagyon limitáltak, csak könyvtár és fájl megengedett (DT_DIR, DT_REG), de a stat pluszban az +S_IFDIR és S_IFREG típusokhoz, S_IFIFO (konzol folyamok: stdin, stdout, stderr), S_IFBLK (Block IO esetén) és S_IFCHR +(Serial IO esetén) típusokat is visszaadhat. + +Továbbá a `getenv` és `setenv` sem POSIX sztandard, mivel az UEFI környezeti változók bináris bitkolbászok. + +Nagyjából ennyi, minden más a megszokott. + +Az elérhető POSIX funkciók listája +---------------------------------- + +### dirent.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| opendir | megszokott, de széles karakterű sztringet is elfogadhat | +| readdir | megszokott | +| rewinddir | megszokott | +| closedir | megszokott | + +Mivel az UEFI számára ismeretlen az eszközfájl és a szimbólikus link, a dirent mezők eléggé limitáltak, és csak DT_DIR +valamint DT_REF típusok támogatottak. + +### stdlib.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| atoi | megszokott, de széles karakterű sztringet és "0x" prefixet is elfogadhat | +| atol | megszokott, de széles karakterű sztringet és "0x" prefixet is elfogadhat | +| strtol | megszokott, de széles karakterű sztringet is elfogadhat | +| malloc | megszokott | +| calloc | megszokott | +| realloc | megszokott | +| free | megszokott | +| abort | megszokott | +| exit | megszokott | +| exit_bs | az egész UEFI szörnyűség elhagyása (exit Boot Services) | +| mbtowc | megszokott (UTF-8 karakter wchar_t-á) | +| wctomb | megszokott (wchar_t-ról UTF-8 karakterré) | +| mbstowcs | megszokott (UTF-8 sztringről wchar_t sztringé) | +| wcstombs | megszokott (wchar_t sztringről UTF-8 sztringé) | +| srand | megszokott | +| rand | megszokott, de EFI_RNG_PROTOCOL-t használ, ha lehetséges | +| getenv | eléggé UEFI specifikus | +| setenv | eléggé UEFI specifikus | + +```c +int exit_bs(); +``` +Exit Boot Services, az UEFI sárkánylakta vidékének elhagyása. Siker esetén 0-át ad vissza. A sikeres hívást követően nem fogsz +tudni visszatérni a main()-ből, direktben kell átadnod a vezérlést. + +```c +uint8_t *getenv(char_t *name, uintn_t *len); +``` +A `name` környezeti változó értékének lekérdezése. Siker esetén a `len` be lesz állítva, és egy frissen allokált buffert +ad vissza. A hívó felelőssége a visszaadott buffer felszabadítása, ha már nem kell. Hiba esetén NULL-t ad vissza. + +```c +int setenv(char_t *name, uintn_t len, uint8_t *data); +``` +A `name` környezeti változó beállítása `len` hosszú `data` értékkel. Siker esetén 1-el tér vissza, hibánál 0-val. + +### stdio.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| remove | megszokott, de széles karakterű sztringet is elfogadhat | +| fopen | megszokott, de széles karakterű sztringet is elfogadhat, mode esetén is | +| fclose | megszokott | +| fflush | megszokott | +| fread | megszokott, csak igazi fájlok és blk io (nem stdin) | +| fwrite | megszokott, csak igazi fájlok és blk io (nem lehet stdout se stderr) | +| fseek | megszokott, csak igazi fájlok és blk io (nem stdin, stdout, stderr) | +| ftell | megszokott, csak igazi fájlok és blk io (nem stdin, stdout, stderr) | +| feof | megszokott, csak igazi fájlok és blk io (nem stdin, stdout, stderr) | +| fprintf | megszokott, de széles sztring is lehet, BUFSIZ, fájl, ser, stdout, stderr | +| printf | megszokott, de széles sztring is lehet, max BUFSIZ, csak stdout | +| sprintf | megszokott, de széles sztring is lehet, max BUFSIZ | +| vfprintf | megszokott, de széles sztring is lehet, BUFSIZ, fájl, ser, stdout, stderr | +| vprintf | megszokott, de széles sztring is lehet, max BUFSIZ, csak stdout | +| vsprintf | megszokott, de széles sztring is lehet, max BUFSIZ | +| snprintf | megszokott, de széles sztring is lehet | +| vsnprintf | megszokott, de széles sztring is lehet | +| getchar | megszokott, blokkol, csak stdin (nincs átirányítás), UNICODE-ot ad vissza | +| getchar_ifany | nem blokkoló, 0-át ad vissza ha nem volt billentyű, egyébként UNICODE-ot | +| putchar | megszokott, csak stdout (nincs átriányítás) | + +A sztring formázás limitált: csak pozitív számokat fogad el prefixnek, `%d` és `%i`, `%x`, `%X`, `%c`, `%s`, `%q` és `%p` (nincs `%e`, +`%f`, `%g`, nincs csillag és dollárjel). Ha a `UEFI_NO_UTF8` definiálva van, akkor a formázás wchar_t-t használ, ezért ilyenkor +támogatott a nem szabványos `%S` (UTF-8 sztring kiírás) és `%Q` (eszképelt UTF-8 sztring kiírás) is. Ezek a funkciók nem +foglalnak le memóriát, cserébe a teljes hossz `BUFSIZ` lehet (8k ha nem definiálták másképp), kivéve azokat a variánsokat, +amik elfogadnak maxlen hossz paramétert. Kényelmi okokból támogatott a `%D` aminek `efi_physical_address_t` paramétert kell +adni, és a memóriát dumpolja, 16 bájtos sorokban. A szám módosítókkal lehet több sort is dumpoltatni, például `%5D` 5 sort +fog dumpolni (80 bájt). + +Fájl megnyitási módok: `"r"` olvasás, `"w"` írás, `"a"` hozzáfűzés. UEFI sajátosságok miatt, `"wd"` könyvtárat hoz létre. + +Speciális "eszköz fájlok", amiket meg lehet nyitni: + +| Név | Leírás | +|---------------------|----------------------------------------------------------------------| +| `/dev/stdin` | ST->ConIn | +| `/dev/stdout` | ST->ConOut, fprintf | +| `/dev/stderr` | ST->StdErr, fprintf | +| `/dev/serial(baud)` | Serial IO protokoll, fread, fwrite, fprintf | +| `/dev/disk(n)` | Block IO protokoll, fseek, ftell, fread, fwrite, feof | + +Block IO esetén az fseek és a buffer méret fread és fwritenál az eszköz blokméretére lesz igazítva. Például fseek(513) +az 512. bájtra pozicionál szabvány blokkméretnél, de 0-ra nagy 4096-os blokkoknál. A blokkméret detektálásához az fstat-ot +lehet használni. +```c +if(!fstat(f, &st)) + block_size = st.st_size / st.st_blocks; +``` +A partíciós GPT tábla értelmezéséhez típusdefiníciók állnak a rendelkezésre, mint `efi_partition_table_header_t` és +`efi_partition_entry_t`, amikkel a beolvasott adatokra lehet mutatni. + +### string.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| memcpy | megszokott, mindenképp bájt | +| memmove | megszokott, mindenképp bájt | +| memset | megszokott, mindenképp bájt | +| memcmp | megszokott, mindenképp bájt | +| memchr | megszokott, mindenképp bájt | +| memrchr | megszokott, mindenképp bájt | +| memmem | megszokott, mindenképp bájt | +| memrmem | megszokott, mindenképp bájt | +| strcpy | széles karakterű sztringet is elfogadhat | +| strncpy | széles karakterű sztringet is elfogadhat | +| strcat | széles karakterű sztringet is elfogadhat | +| strncat | széles karakterű sztringet is elfogadhat | +| strcmp | széles karakterű sztringet is elfogadhat | +| strncmp | széles karakterű sztringet is elfogadhat | +| strdup | széles karakterű sztringet is elfogadhat | +| strchr | széles karakterű sztringet is elfogadhat | +| strrchr | széles karakterű sztringet is elfogadhat | +| strstr | széles karakterű sztringet is elfogadhat | +| strtok | széles karakterű sztringet is elfogadhat | +| strtok_r | széles karakterű sztringet is elfogadhat | +| strlen | széles karakterű sztringet is elfogadhat | + +### sys/stat.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| stat | megszokott, de széles karakterű sztringet is elfogadhat | +| fstat | UEFI alatt nincs fd, ezért FILE\*-ot használ | +| mkdir | megszokott, de széles karakterű sztringet is elfogadhat, mode nem használt | + +Mivel az UEFI számára ismeretlen az eszköz major és minor valamint az inode szám, a struct stat mezői limitáltak. +Az `fstat` implementációja az stdio.c-ben található, mivel el kell érnie bizonyos ott definiált statikus változókat. + +### time.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| localtime | paraméterek nem használtak, mindig a pontos időt adja vissza struct tm-ben | +| mktime | megszokott | +| time | megszokott | + +### unistd.h + +| Funkció | Leírás | +|---------------|----------------------------------------------------------------------------| +| usleep | megszokott (BS->Stall hívást használ) | +| sleep | megszokott | +| unlink | megszokott, de széles karakterű sztringet is elfogadhat | +| rmdir | megszokott, de széles karakterű sztringet is elfogadhat | + +UEFI szolgáltatások elérése +--------------------------- + +Elég valószínű, hogy direktben UEFI szolgáltatást kell majd hívni. Ehhez a POSIX-UEFI néhány globális változót biztosít +az `uefi.h`-ban definiálva: + +| Globális változó | Leírás | +|------------------|----------------------------------------------------------| +| `*BS`, `gBS` | *efi_boot_services_t*, mutató a Boot Time Services-ra | +| `*RT`, `gRT` | *efi_runtime_t*, mutató a Runtime Services-ra | +| `*ST`, `gST` | *efi_system_table_t*, mutató az UEFI System Table-re | +| `IM` | a betöltött fájlod *efi_handle_t*-je (loaded image) | + +Az EFI struktúrák, enumok, típusdefiníciók, defineok mind ANSI C szabványos POSIX stílusúra lettek konvertálva, például +BOOLEAN -> boolean_t, UINTN -> uintn_t, EFI_MEMORY_DESCRIPTOR -> efi_memory_descriptor_t, és persze +EFI_BOOT_SERVICES -> efi_boot_services_t. + +UEFI funkciók hívása pont olyan egyszerű, mint EDK II esetén, csak meg kell hívni, nincs szükség "uefi_call_wrapper"-re: +```c + ST->ConOut->OutputString(ST->ConOut, L"Hello World!\r\n"); +``` +(Megjegyzés: a printf-el ellentétben az OutputString-nél mindig kell `L""` és ki kell írni `L"\r"`-t a `L"\n"` előtt. Ezek +azok az apróságok, amikkel a POSIX-UEFI kényelmesebbé teszi az életedet.) + +Van továbbá két, nem POSIX szabványos függvény a könyvtárban. Az egyik az `exit_bs()` az UEFI elhagyására, a másik a nem +blokkoló `getchar_ifany()`. + +A gnu-efi-vel ellentétben a POSIX-UEFI nem szennyezi a névteret nemhasznált GUID változókkal. Csak define-okat biztosít, +ezért mindig neked kell létrehozni a GUID példányt, ha és amikor szükséged van rá. + +Példa: +```c +efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +efi_gop_t *gop = NULL; + +status = BS->LocateProtocol(&gopGuid, NULL, (void**)&gop); +``` + +Szintén a gnu-efi-vel ellentétben a POSIX-UEFI nem biztosítja a szabványos UEFI fejlécfájlokat. Úgy veszi, hogy azokat +vagy az EDk II-ből vagy a gnu.efi-ből átmásoltad az /usr/include/efi alá, és biztosítja, hogy be legyenek húzva névtér +ütközés nélkül. Maga a POSIX-UEFI csak egy nagyon minimális mennyiségű típusdefiniciót biztosít (és azokat is POSIX-osított +névvel). +```c +#include +#include /* ez működik! Mind a POSIX-UEFI és az EDK II / gnu-efi typedef-ek elérhetők */ +``` +Ennek az az előnye, hogy használhatod a POSIX-UEFI egyszerű könyvtárát és fordító környezetét, ugyanakkor hozzáférhetsz +a legfrissebb protokoll és interfész definíciókoz egyaránt. + +__FONTOS FIGYELMEZTETÉS__ + +Bizonyos esetekben a GNU-EFI hedörök és a Clang kombinációja hibásan 32 bites `uint64_t` típust eredményezhet. Ha ez előjön, +akkor a +```c +#undef __STDC_VERSION__ +#include +#include +``` +kerülőmegoldás lehet a problémára, mivel így nem húzza be az stdint.h-t, helyette az efibind.h fogja definiálni az uint64_t +típust mint `unsigned long long`. + +Licensz +------- + +POSIX_UEFI az MIT licensz alatt kerül terjesztésre. + +Hozzájárulások +-------------- + +Szeretnék köszönetet mondani @vladimir132 -nek az alapos tesztelésért és a pontos és részletes visszajelzésekért. + +Ez minden, + +bzt diff --git a/libs/posix-uefi/README.md b/libs/posix-uefi/README.md new file mode 100644 index 0000000..ac4cf6d --- /dev/null +++ b/libs/posix-uefi/README.md @@ -0,0 +1,389 @@ +POSIX-UEFI +========== + +
We hate that horrible and ugly UEFI API, we want the usual POSIX!
+ +------------------------------------------------------------------------------------------------------------------------ + +NOTE: a smartypants on reddit is worried that I'm supposedly "hiding something" because of the use of `-Wno-builtin-declaration-mismatch` +(gcc) and `-Wno-incompatible-library-redeclaration` (Clang) flags. **Here's my answer to you: I hide nothing**, that flag is only +needed because you can disable transparent UTF-8 conversion. You see, under the hood UEFI uses 16 bit characters, and for example +`strlen(wchar_t *str)` or `main(int argc, wchar_t *argv)` isn't exactly POSIX-standard, that's why there's a need for that flag. +You should know that had you have spent more time learning or just *reading this README* instead of falsely accusing others on reddit. + +------------------------------------------------------------------------------------------------------------------------ + +This is a very small build environment that helps you to develop for UEFI under Linux (and other POSIX systems). It was +greatly inspired by [gnu-efi](https://sourceforge.net/projects/gnu-efi) (big big kudos to those guys), but it is a lot +smaller, easier to integrate (works with LLVM Clang and GNU gcc both) and easier to use because it provides a POSIX like +API for your UEFI application. + +An UEFI environment consist of two parts: a firmware with GUID protocol interfaces and a user library. We cannot change +the former, but we can make the second friendlier. That's what POSIX-UEFI does for your application. It is a small API +wrapper library around the GUID protocols, not a fully blown POSIX compatible libc implementation. + +You have two options on how to integrate it into your project: + +Distributing as Static Library +------------------------------ + +Same method as with gnu-efi, not really recommended. In the `uefi` directory, run +```sh +$ USE_GCC=1 make +``` +This will create `build/uefi` with all the necessary files in it. These are: + + - **crt0.o**, the run-time that bootstraps POSIX-UEFI + - **link.ld**, the linker script you must use with POSIX-UEFI (same as with gnu-efi) + - **libuefi.a**, the library itself + - **uefi.h**, the all-in-one C / C++ header + +You can use this and link your application with it, but you won't be able to recompile it, plus you're on your own with +the linking and converting. + +Strictly speaking you'll only need **crt0.o** and **link.ld**, that will get you started and will call your application's +"main()", but to get libc functions like memcmp, strcpy, malloc or fopen, you'll have to link with **libuefi.a** too. + +For now this only works with gcc, because Clang is configured in a way to directly create PE files, so it cannot create +nor link with static ELF .a files. + +Distributing as Source +---------------------- + +This is the preferred way, as it also provides a Makefile to set up your toolchain properly. + + 1. simply copy the `uefi` directory into your source tree (or set up a git submodule and a symlink). A dozen files, about 132K in total. + 2. create an extremely simple **Makefile** like the one below + 3. compile your code for UEFI by running `make` + +``` +TARGET = helloworld.efi +include uefi/Makefile +``` +An example **helloworld.c** goes like this: +```c +#include + +int main(int argc, char **argv) +{ + printf("Hello World!\n"); + return 0; +} +``` +By default it uses Clang + lld, and PE is generated directly without conversion. If `USE_GCC` is set, then the host native's +GNU gcc + ld is used to create a shared object and get converted into an .efi file with objcopy, just like how gnu-efi does. + +**NOTE**: if you don't want to clone this entire repo, just the `uefi` directory, +``` +git clone --no-checkout https://gitlab.com/bztsrc/posix-uefi.git . +git sparse-checkout set --no-cone '/uefi/*' +git checkout +``` + +### Available Makefile Options + +| Variable | Description | +|------------|-------------------------------------------------------------------------------------------------------------------| +| `TARGET` | the target application (required) | +| `SRCS` | list of source files you want to compile (defaults to \*.c \*.S) | +| `CFLAGS` | compiler flags you want to use (empty by default, like "-Wall -pedantic -std=c99") | +| `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) | +| `EXTRA` | any additional object files you might want to link with, these are also called as makefile rules before compiling | +| `ALSO` | additional makefile rules to be called after compiling | +| `OUTDIR` | if given, then your project's object files are generated into this directory (by default not set) | +| `USE_GCC` | set this if you want native GNU gcc + ld + objcopy instead of LLVM Clang + Lld | +| `ARCH` | the target architecture | + +Here's a more advanced **Makefile** example: +``` +ARCH = x86_64 +TARGET = helloworld.efi +SRCS = $(wildcard *.c) +CFLAGS = -pedantic -Wall -Wextra -Werror --std=c11 -O2 +LDFLAGS = +LIBS = -lm +OUTDIR = build/loader + +USE_GCC = 1 +include uefi/Makefile +``` +The build environment configurator was created in a way that it can handle any number of architectures, however only +`x86_64` crt0 has been throughfully tested for now. There's an `aarch64` and a `riscv64` crt0 too, but since I don't +have neither an ARM UEFI, nor a RISC-V UEFI board, these **haven't been tested at all**. Should work though. If you want +to port it to another architecture, all you need is a setjmp struct in uefi.h, and an appropriate crt_X.c file. That's +it. Everything else was coded in an architecture independent way. + +### Available Configuration Options + +These can be set at the beginning of `uefi.h`. + +| Define | Description | +|-----------------------|-------------------------------------------------------------------------------------------| +| `UEFI_NO_UTF8` | Do not use transparent UTF-8 conversion between the application and the UEFI interface | +| `UEFI_NO_TRACK_ALLOC` | Do not keep track of allocated buffers (faster, but causes out of bound reads on realloc) | + +Notable Differences to POSIX libc +--------------------------------- + +This library is nowhere near as complete as glibc or musl for example. It only provides the very basic libc functions +for you, because simplicity was one of its main goals. It is the best to say this is just wrapper around the UEFI API, +rather than a POSIX compatible libc. + +All strings in the UEFI environment are stored with 16 bits wide characters. The library provides `wchar_t` type for that, +and the `UEFI_NO_UTF8` define to convert between `char` and `wchar_t` transparently. If you have `UEFI_NO_UTF8`, then for +example your main() will NOT be 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) will use this wide character type too. For this reason, +you must specify your string literals with `L""` and characters with `L''`. To handle both configurations, `char_t` type is +defined, which is either `char` or `wchar_t`, and the `CL()` macro which might add the `L` prefix to constant literals. +Functions that are supposed to handle characters in int type (like `getchar`, `putchar`), do not truncate to unsigned char, +rather to wchar_t. + +Sadly UEFI has no concept of reallocation. AllocatePool does not accept input, and there's no way to query the size of an +already allocated buffer. So we are left with two bad options with `realloc`: +1. we keep track of sizes ourselves, which means more complexcity and a considerable overhead, so performance loss. +2. make peace with the fact that copying data to the new buffer unavoidably reads out of bounds from the old buffer. +You can choose this latter with the `UEFI_NO_TRACK_ALLOC` define. + +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 (for console streams: stdin, stdout, stderr), S_IFBLK (for Block IO) and S_IFCHR (for Serial IO) also +returned. + +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. + +List of Provided POSIX Functions +-------------------------------- + +### dirent.h + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| opendir | as usual, but might accept wide char strings | +| readdir | as usual | +| rewinddir | as usual | +| closedir | as usual | + +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 + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| atoi | as usual, but might accept wide char strings and understands "0x" prefix | +| atol | as usual, but might accept wide char strings and understands "0x" prefix | +| strtol | as usual, but might accept wide char strings | +| malloc | as usual | +| calloc | as usual | +| realloc | as usual | +| free | as usual | +| abort | as usual | +| exit | as usual | +| exit_bs | leave this entire UEFI bullshit behind (exit Boot Services) | +| mbtowc | as usual (UTF-8 char to wchar_t) | +| wctomb | as usual (wchar_t to UTF-8 char) | +| mbstowcs | as usual (UTF-8 string to wchar_t string) | +| wcstombs | as usual (wchar_t string to UTF-8 string) | +| srand | as usual | +| 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. You won't be able to return from main() after calling this successfully, you must +transfer control directly. + +```c +uint8_t *getenv(char_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(char_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 + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| remove | as usual, but might accept wide char strings | +| fopen | as usual, but might accept wide char strings, also for mode | +| fclose | as usual | +| fflush | as usual | +| fread | as usual, only real files and blk io accepted (no stdin) | +| fwrite | as usual, only real files and blk io accepted (no stdout nor stderr) | +| fseek | as usual, only real files and blk io accepted (no stdin, stdout, stderr) | +| ftell | as usual, only real files and blk io accepted (no stdin, stdout, stderr) | +| feof | as usual, only real files and blk io accepted (no stdin, stdout, stderr) | +| fprintf | as usual, might be wide char strings, BUFSIZ, files, ser, stdout, stderr | +| printf | as usual, might be wide char strings, max BUFSIZ, stdout only | +| sprintf | as usual, might be wide char strings, max BUFSIZ | +| vfprintf | as usual, might be wide char strings, BUFSIZ, files, ser, stdout, stderr | +| vprintf | as usual, might be wide char strings, max BUFSIZ, stdout only | +| vsprintf | as usual, might be wide char strings, max BUFSIZ | +| snprintf | as usual, might be wide char strings | +| vsnprintf | as usual, might be wide char strings | +| getchar | as usual, blocking, stdin only (no stream redirects), returns UNICODE | +| getchar_ifany | non-blocking, returns 0 if there was no key press, UNICODE otherwise | +| putchar | as usual, stdout only (no stream redirects) | + +String formating is limited; only supports padding via positive number prefixes, `%d`, `%i`, `%x`, `%X`, `%c`, `%s`, `%q` and +`%p` (no `%e`, `%f`, `%g`, no asterisk and dollar). When `UEFI_NO_UTF8` is defined, then formating operates on wchar_t, so +it also supports the non-standard `%S` (printing an UTF-8 string) and `%Q` (printing an escaped UTF-8 string). These +functions don't allocate memory, but in return the total length of the output string cannot be longer than `BUFSIZ` +(8k if you haven't defined otherwise), except for the variants which have a maxlen argument. For convenience, `%D` requires +`efi_physical_address_t` as argument, and it dumps memory, 16 bytes or one line at once. With the padding modifier you can +dump more lines, for example `%5D` gives you 5 lines (80 dumped bytes). + +File open modes: `"r"` read, `"w"` write, `"a"` append. Because of UEFI peculiarities, `"wd"` creates directory. + +Special "device files" you can open: + +| Name | Description | +|---------------------|----------------------------------------------------------------------| +| `/dev/stdin` | returns ST->ConIn | +| `/dev/stdout` | returns ST->ConOut, fprintf | +| `/dev/stderr` | returns ST->StdErr, fprintf | +| `/dev/serial(baud)` | returns Serial IO protocol, fread, fwrite, fprintf | +| `/dev/disk(n)` | returns Block IO protocol, fseek, ftell, fread, fwrite, feof | + +With Block IO, fseek and buffer size for fread and fwrite is always truncated to the media's block size. So fseek(513) +for example will seek to 512 with standard block sizes, and 0 with large 4096 block sizes. To detect the media's block +size, use fstat. +```c +if(!fstat(f, &st)) + block_size = st.st_size / st.st_blocks; +``` +To interpret a GPT, there are typedefs like `efi_partition_table_header_t` and `efi_partition_entry_t` which you can point +to the read data. + +### string.h + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| memcpy | as usual, works on bytes | +| memmove | as usual, works on bytes | +| memset | as usual, works on bytes | +| memcmp | as usual, works on bytes | +| memchr | as usual, works on bytes | +| memrchr | as usual, works on bytes | +| memmem | as usual, works on bytes | +| memrmem | as usual, works on bytes | +| strcpy | might work on wide char strings | +| strncpy | might work on wide char strings | +| strcat | might work on wide char strings | +| strncat | might work on wide char strings | +| strcmp | might work on wide char strings | +| strncmp | might work on wide char strings | +| strdup | might work on wide char strings | +| strchr | might work on wide char strings | +| strrchr | might work on wide char strings | +| strstr | might work on wide char strings | +| strtok | might work on wide char strings | +| strtok_r | might work on wide char strings | +| strlen | might work on wide char strings | + +### sys/stat.h + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| stat | as usual, but might accept wide char strings | +| fstat | UEFI doesn't have fd, so it uses FILE\* | +| mkdir | as usual, but might accept wide char strings, and mode unused | + +Because UEFI has no concept of device major and minor number nor of inodes, struct stat's fields are limited. +The actual implementation of `fstat` is in stdio.c, because it needs to access static variables defined there. + +### time.h + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| localtime | argument unused, always returns current time in struct tm | +| mktime | as usual | +| time | as usual | + +### unistd.h + +| Function | Description | +|---------------|----------------------------------------------------------------------------| +| usleep | as usual (uses BS->Stall) | +| sleep | as usual | +| unlink | as usual, but might accept wide char strings | +| rmdir | as usual, but might accept wide char strings | + +Accessing UEFI Services +----------------------- + +It is very likely that you want to call UEFI specific functions directly. For that, POSIX-UEFI specifies some globals +in `uefi.h`: + +| Global Variable | Description | +|-----------------|----------------------------------------------------------| +| `*BS`, `gBS` | *efi_boot_services_t*, pointer to the Boot Time Services | +| `*RT`, `gRT` | *efi_runtime_t*, pointer to the Runtime Services | +| `*ST`, `gST` | *efi_system_table_t*, pointer to the UEFI System Table | +| `IM` | *efi_handle_t* of your Loaded Image | + +The EFI structures, enums, typedefs and defines are all converted to ANSI C standard POSIX style, for example +BOOLEAN -> boolean_t, UINTN -> uintn_t, EFI_MEMORY_DESCRIPTOR -> efi_memory_descriptor_t, and of course +EFI_BOOT_SERVICES -> efi_boot_services_t. + +Calling UEFI functions is as simple as with EDK II, just do the call, no need for "uefi_call_wrapper": +```c + ST->ConOut->OutputString(ST->ConOut, L"Hello World!\r\n"); +``` +(Note: unlike with printf, with OutputString you must use `L""` and also print carrige return `L"\r"` before `L"\n"`. These +are the small things that POSIX-UEFI does for you to make your life comfortable.) + +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 version `getchar_ifany()`. + +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. + +Example: +```c +efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +efi_gop_t *gop = NULL; + +status = BS->LocateProtocol(&gopGuid, NULL, (void**)&gop); +``` + +Also unlike gnu-efi, POSIX-UEFI does not provide standard EFI headers. It expects that you have installed those under +/usr/include/efi from EDK II or gnu-efi, and POSIX-UEFI makes it possible to use those system wide headers without +naming conflicts. POSIX-UEFI itself ships the very minimum set of typedefs and structs (with POSIX-ized names). +```c +#include +#include /* 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. + +__IMPORTANT NOTE__ + +In some cases the combination of GNU-EFI headers and Clang might incorrectly define `uint64_t` as 32 bits. If this happens, +then +```c +#undef __STDC_VERSION__ +#include +#include +``` +should workaround the problem by avoiding the inclusion of stdint.h and defining uint64_t by efibind.h as `unsigned long long`. + +License +------- + +POSIX_UEFI is licensed under the terms of the MIT license. + +Contributors +------------ + +I'd like to say thanks to @vladimir132 for a through testing and very accurate and detailed feedbacks. + +Cheers, + +bzt diff --git a/libs/posix-uefi/uefi/crt_aarch64.c b/libs/posix-uefi/uefi/crt_aarch64.c new file mode 100644 index 0000000..82324a5 --- /dev/null +++ b/libs/posix-uefi/uefi/crt_aarch64.c @@ -0,0 +1,239 @@ +/* + * 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 + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +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 */ +#endif + +/* 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; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " ldr x2, =ImageBase\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 */ + __asm__ __volatile__ ( + " .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" + ); + __asm__ __volatile__ ( + " .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 + */ +efi_status_t 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, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + 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; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* 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 = (int)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 = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); + return ret; +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/libs/posix-uefi/uefi/crt_riscv64.c b/libs/posix-uefi/uefi/crt_riscv64.c new file mode 100644 index 0000000..77b52ae --- /dev/null +++ b/libs/posix-uefi/uefi/crt_riscv64.c @@ -0,0 +1,270 @@ +/* + * crt_riscv64.c + * + * Copyright (C) 2023 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 + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +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_RISCV_RELATIVE 3 /* Adjust by program base */ +#endif + +/* 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; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " lla a2, ImageBase\n" + " lui a3, %hi(_DYNAMIC)\n" + " addi a3, a3, %lo(_DYNAMIC)\n" + " call 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 */ + __asm__ __volatile__ ( + " .p2align 3\n" + " .globl setjmp\n" + "setjmp:\n" + " sd ra, 0(a0)\n" + " sd sp, 8(a0)\n" + " sd s0, 16(a0)\n" + " sd s1, 24(a0)\n" + " sd s2, 32(a0)\n" + " sd s3, 40(a0)\n" + " sd s4, 48(a0)\n" + " sd s5, 56(a0)\n" + " sd s6, 64(a0)\n" + " sd s7, 72(a0)\n" + " sd s8, 80(a0)\n" + " sd s9, 88(a0)\n" + " sd s10, 96(a0)\n" + " sd s11, 104(a0)\n" +#ifndef __riscv_float_abi_soft + " fsd fs0, 112(a0)\n" + " fsd fs1, 120(a0)\n" + " fsd fs2, 128(a0)\n" + " fsd fs3, 136(a0)\n" + " fsd fs4, 144(a0)\n" + " fsd fs5, 152(a0)\n" + " fsd fs6, 160(a0)\n" + " fsd fs7, 168(a0)\n" + " fsd fs8, 176(a0)\n" + " fsd fs9, 184(a0)\n" + " fsd fs10,192(a0)\n" + " fsd fs11,200(a0)\n" +#endif + " li a0, 0\n" + " ret\n" + ); + __asm__ __volatile__ ( + " .globl longjmp\n" + "longjmp:\n" + " ld ra, 0(a0)\n" + " ld sp, 8(a0)\n" + " ld s0, 16(a0)\n" + " ld s1, 24(a0)\n" + " ld s2, 32(a0)\n" + " ld s3, 40(a0)\n" + " ld s4, 48(a0)\n" + " ld s5, 56(a0)\n" + " ld s6, 64(a0)\n" + " ld s7, 72(a0)\n" + " ld s8, 80(a0)\n" + " ld s9, 88(a0)\n" + " ld s10, 96(a0)\n" + " ld s11, 104(a0)\n" +#ifndef __riscv_float_abi_soft + " fld fs0, 112(a0)\n" + " fld fs1, 120(a0)\n" + " fld fs2, 128(a0)\n" + " fld fs3, 136(a0)\n" + " fld fs4, 144(a0)\n" + " fld fs5, 152(a0)\n" + " fld fs6, 160(a0)\n" + " fld fs7, 168(a0)\n" + " fld fs8, 176(a0)\n" + " fld fs9, 184(a0)\n" + " fld fs10,192(a0)\n" + " fld fs11,200(a0)\n" +#endif + " seqz a0, a1\n" + " add a0, a0, a1\n" + " ret\n" + ); +} + +/** + * Initialize POSIX-UEFI and call the application's main() function + */ +efi_status_t 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, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + 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_RISCV_RELATIVE) + { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* 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 = (int)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 = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); + return ret; +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/libs/posix-uefi/uefi/crt_x86_64.c b/libs/posix-uefi/uefi/crt_x86_64.c new file mode 100644 index 0000000..b146bb3 --- /dev/null +++ b/libs/posix-uefi/uefi/crt_x86_64.c @@ -0,0 +1,241 @@ +/* + * crt_x86_64.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 + +/* this is implemented by the application */ +extern int main(int argc, char_t **argv); + +/* definitions for elf relocations */ +#ifndef __clang__ +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_X86_64_RELATIVE 8 /* Adjust by program base */ +#endif + +/* 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; +#ifndef UEFI_NO_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap(void) +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " lea ImageBase(%rip), %rdi\n" + " lea _DYNAMIC(%rip), %rsi\n" + " call 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 */ + __asm__ __volatile__ ( + " .globl setjmp\n" + "setjmp:\n" + " pop %rsi\n" + " movq %rbx,0x00(%rdi)\n" + " movq %rsp,0x08(%rdi)\n" + " push %rsi\n" + " movq %rbp,0x10(%rdi)\n" + " movq %r12,0x18(%rdi)\n" + " movq %r13,0x20(%rdi)\n" + " movq %r14,0x28(%rdi)\n" + " movq %r15,0x30(%rdi)\n" + " movq %rsi,0x38(%rdi)\n" + " xor %rax,%rax\n" + " ret\n" + ); + __asm__ __volatile__ ( + " .globl longjmp\n" + "longjmp:\n" + " movl %esi, %eax\n" + " movq 0x00(%rdi), %rbx\n" + " movq 0x08(%rdi), %rsp\n" + " movq 0x10(%rdi), %rbp\n" + " movq 0x18(%rdi), %r12\n" + " movq 0x20(%rdi), %r13\n" + " movq 0x28(%rdi), %r14\n" + " movq 0x30(%rdi), %r15\n" + " xor %rdx,%rdx\n" + " mov $1,%rcx\n" + " cmp %rax,%rdx\n" + " cmove %rcx,%rax\n" + " jmp *0x38(%rdi)\n" + ); +} + +/** + * Initialize POSIX-UEFI and call the application's main() function + */ +efi_status_t uefi_init ( +#ifndef __clang__ + uintptr_t ldbase, Elf64_Dyn *dyn, efi_system_table_t *systab, efi_handle_t image +#else + efi_handle_t image, efi_system_table_t *systab +#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, i, ret; + wchar_t **argv = NULL; +#ifndef UEFI_NO_UTF8 + int j; + char *s; +#endif +#ifndef __clang__ + 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_X86_64_RELATIVE) + { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* make sure SSE is enabled, because some say there are buggy firmware in the wild not doing that */ + __asm__ __volatile__ ( + " movq %cr0, %rax\n" + " andb $0xF1, %al\n" + " movq %rax, %cr0\n" + " movq %cr4, %rax\n" + " orw $3 << 9, %ax\n" + " mov %rax, %cr4\n" + ); + /* failsafes, should never happen */ + if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol || + !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool) + return EFI_UNSUPPORTED; + /* 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 = (int)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 = (int)shi->Argc; argv = shi->Argv; } + } + /* call main */ +#ifndef UEFI_NO_UTF8 + if(argc && argv) { + ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1); + for(i = 0; i < argc; i++) + for(j = 0; argv[i] && argv[i][j]; j++) + ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3); + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * (int)sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s; + for(j = 0; argv[i] && argv[i][j]; j++) { + if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else + if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else + { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; } + } + *s++ = 0; + } + } + } + ret = main(argc, (char**)__argvutf8); + if(__argvutf8) BS->FreePool(__argvutf8); +#else + ret = main(argc, argv); +#endif + return ret ? EFIERR(ret) : EFI_SUCCESS; +} diff --git a/libs/posix-uefi/uefi/dirent.c b/libs/posix-uefi/uefi/dirent.c new file mode 100644 index 0000000..402011c --- /dev/null +++ b/libs/posix-uefi/uefi/dirent.c @@ -0,0 +1,76 @@ +/* + * dirent.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 Implementing functions which are defined in dirent.h + * + */ + +#include + +extern void __stdio_seterrno(efi_status_t status); +static struct dirent __dirent; + +DIR *opendir (const char_t *__name) +{ + DIR *dp = (DIR*)fopen(__name, CL("rd")); + if(dp) rewinddir(dp); + return dp; +} + +struct dirent *readdir (DIR *__dirp) +{ + efi_status_t status; + efi_file_info_t info; + uintn_t bs = sizeof(efi_file_info_t); + memset(&__dirent, 0, sizeof(struct dirent)); + status = __dirp->Read(__dirp, &bs, &info); + if(EFI_ERROR(status) || !bs) { + if(EFI_ERROR(status)) __stdio_seterrno(status); + else errno = 0; + return NULL; + } + __dirent.d_type = info.Attribute & EFI_FILE_DIRECTORY ? DT_DIR : DT_REG; +#ifndef UEFI_NO_UTF8 + __dirent.d_reclen = (unsigned short int)wcstombs(__dirent.d_name, info.FileName, FILENAME_MAX - 1); +#else + __dirent.d_reclen = strlen(info.FileName); + strncpy(__dirent.d_name, info.FileName, FILENAME_MAX - 1); +#endif + return &__dirent; +} + +void rewinddir (DIR *__dirp) +{ + if(__dirp) + __dirp->SetPosition(__dirp, 0); +} + +int closedir (DIR *__dirp) +{ + return fclose((FILE*)__dirp); +} + + diff --git a/libs/posix-uefi/uefi/elf_aarch64_efi.lds b/libs/posix-uefi/uefi/elf_aarch64_efi.lds new file mode 100644 index 0000000..836d982 --- /dev/null +++ b/libs/posix-uefi/uefi/elf_aarch64_efi.lds @@ -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) } +} diff --git a/libs/posix-uefi/uefi/elf_riscv64_efi.lds b/libs/posix-uefi/uefi/elf_riscv64_efi.lds new file mode 100644 index 0000000..6f1936b --- /dev/null +++ b/libs/posix-uefi/uefi/elf_riscv64_efi.lds @@ -0,0 +1,64 @@ +OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") +OUTPUT_ARCH(riscv) +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.text : { *(.rela.text) *(.rela.text*) } + .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) } +} diff --git a/libs/posix-uefi/uefi/elf_x86_64_efi.lds b/libs/posix-uefi/uefi/elf_x86_64_efi.lds new file mode 100644 index 0000000..7be5902 --- /dev/null +++ b/libs/posix-uefi/uefi/elf_x86_64_efi.lds @@ -0,0 +1,76 @@ +/* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) +SECTIONS +{ + . = 0; + ImageBase = .; + /* .hash and/or .gnu.hash MUST come first! */ + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + . = ALIGN(4096); + .eh_frame : + { + *(.eh_frame) + } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + . = ALIGN(4096); + .reloc : + { + *(.reloc) + } + . = ALIGN(4096); + .data : + { + _data = .; + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + /* the EFI loader doesn't seem to like a .bss section, so we stick + it all into .data: */ + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + .note.gnu.build-id : { *(.note.gnu.build-id) } + + _edata = .; + _data_size = . - _etext; + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .ignored.reloc : + { + *(.rela.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/libs/posix-uefi/uefi/qsort.c b/libs/posix-uefi/uefi/qsort.c new file mode 100644 index 0000000..d6563c9 --- /dev/null +++ b/libs/posix-uefi/uefi/qsort.c @@ -0,0 +1,154 @@ +/* + * qsort.c + * + * @brief from OpenBSD + */ + +/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include + +static __inline char *med3(char *, char *, char *, __compar_fn_t cmp); +static __inline void swapfunc(char *, char *, int, int); +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; +static __inline void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) +static __inline char * +med3(char *a, char *b, char *c, __compar_fn_t cmp) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void qsort(void *aa, size_t n, size_t es, __compar_fn_t cmp) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + char *a = aa; +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - (int)es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + qsort(a, r / es, es, cmp); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/libs/posix-uefi/uefi/stat.c b/libs/posix-uefi/uefi/stat.c new file mode 100644 index 0000000..017a4f8 --- /dev/null +++ b/libs/posix-uefi/uefi/stat.c @@ -0,0 +1,68 @@ +/* + * stat.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 Implementing functions which are defined in sys/stat.h + * + */ + +#include + +/* fstat is in stdio.c because we can't access static variables otherwise... */ + +int stat (const char_t *__file, struct stat *__buf) +{ + int ret; + FILE *f; + + if(!__file || !*__file || !__buf) { + errno = EINVAL; + return -1; + } + f = fopen(__file, CL("*")); + if(!f) { + memset(__buf, 0, sizeof(struct stat)); + return -1; + } + ret = fstat(f, __buf); + fclose(f); + return ret; +} + +extern int mkdir (const char_t *__path, mode_t __mode) +{ + FILE *f; + (void)__mode; + if(!__path || !*__path) { + errno = EINVAL; + return -1; + } + f = fopen(__path, CL("wd")); + if(!f) { + return -1; + } + fclose(f); + return 0; +} diff --git a/libs/posix-uefi/uefi/stdio.c b/libs/posix-uefi/uefi/stdio.c new file mode 100644 index 0000000..350ff7b --- /dev/null +++ b/libs/posix-uefi/uefi/stdio.c @@ -0,0 +1,816 @@ +/* + * stdio.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 Implementing functions which are defined in stdio.h + * + */ + +#include + +static efi_file_handle_t *__root_dir = NULL; +static efi_serial_io_protocol_t *__ser = NULL; +static block_file_t *__blk_devs = NULL; +static uintn_t __blk_ndevs = 0; +extern time_t __mktime_efi(efi_time_t *t); +void __stdio_cleanup(void); +void __stdio_seterrno(efi_status_t status); +int __remove (const char_t *__filename, int isdir); + +void __stdio_cleanup(void) +{ +#ifndef UEFI_NO_UTF8 + if(__argvutf8) + BS->FreePool(__argvutf8); +#endif + if(__blk_devs) { + free(__blk_devs); + __blk_devs = NULL; + __blk_ndevs = 0; + } +} + +void __stdio_seterrno(efi_status_t status) +{ + switch((int)(status & 0xffff)) { + case EFI_WRITE_PROTECTED & 0xffff: errno = EROFS; break; + case EFI_ACCESS_DENIED & 0xffff: errno = EACCES; break; + case EFI_VOLUME_FULL & 0xffff: errno = ENOSPC; break; + case EFI_NOT_FOUND & 0xffff: errno = ENOENT; break; + case EFI_INVALID_PARAMETER & 0xffff: errno = EINVAL; break; + default: errno = EIO; break; + } +} + +int fstat (FILE *__f, struct stat *__buf) +{ + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t); + efi_status_t status; + uintn_t i; + + if(!__f || !__buf) { + errno = EINVAL; + return -1; + } + memset(__buf, 0, sizeof(struct stat)); + if(__f == stdin) { + __buf->st_mode = S_IREAD | S_IFIFO; + return 0; + } + if(__f == stdout || __f == stderr) { + __buf->st_mode = S_IWRITE | S_IFIFO; + return 0; + } + if(__ser && __f == (FILE*)__ser) { + __buf->st_mode = S_IREAD | S_IWRITE | S_IFCHR; + return 0; + } + for(i = 0; i < __blk_ndevs; i++) + if(__f == (FILE*)__blk_devs[i].bio) { + __buf->st_mode = S_IREAD | S_IWRITE | S_IFBLK; + __buf->st_size = (off_t)__blk_devs[i].bio->Media->BlockSize * ((off_t)__blk_devs[i].bio->Media->LastBlock + 1); + __buf->st_blocks = __blk_devs[i].bio->Media->LastBlock + 1; + return 0; + } + status = __f->GetInfo(__f, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return -1; + } + __buf->st_mode = S_IREAD | + (info.Attribute & EFI_FILE_READ_ONLY ? 0 : S_IWRITE) | + (info.Attribute & EFI_FILE_DIRECTORY ? S_IFDIR : S_IFREG); + __buf->st_size = (off_t)info.FileSize; + __buf->st_blocks = (blkcnt_t)info.PhysicalSize; + __buf->st_atime = __mktime_efi(&info.LastAccessTime); + __buf->st_mtime = __mktime_efi(&info.ModificationTime); + __buf->st_ctime = __mktime_efi(&info.CreateTime); + return 0; +} + +int fclose (FILE *__stream) +{ + efi_status_t status = EFI_SUCCESS; + uintn_t i; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) + return 1; + status = __stream->Close(__stream); + free(__stream); + return !EFI_ERROR(status); +} + +int fflush (FILE *__stream) +{ + efi_status_t status = EFI_SUCCESS; + uintn_t i; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr || (__ser && __stream == (FILE*)__ser)) { + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + return 1; + } + status = __stream->Flush(__stream); + return !EFI_ERROR(status); +} + +int __remove (const char_t *__filename, int isdir) +{ + efi_status_t status; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; + /* little hack to support read and write mode for Delete() and stat() without create mode or checks */ + FILE *f = fopen(__filename, CL("*")); + if(errno) + return 1; + if(!f || f == stdin || f == stdout || f == stderr || (__ser && f == (FILE*)__ser)) { + errno = EBADF; + return 1; + } + for(i = 0; i < __blk_ndevs; i++) + if(f == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return 1; + } + if(isdir != -1) { + status = f->GetInfo(f, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + if(isdir == 0 && (info.Attribute & EFI_FILE_DIRECTORY)) { + fclose(f); errno = EISDIR; + return -1; + } + if(isdir == 1 && !(info.Attribute & EFI_FILE_DIRECTORY)) { + fclose(f); errno = ENOTDIR; + return -1; + } + } + status = f->Delete(f); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + fclose(f); + return -1; + } + /* no need for fclose(f); */ + free(f); + return 0; +} + +int remove (const char_t *__filename) +{ + return __remove(__filename, -1); +} + +FILE *fopen (const char_t *__filename, const char_t *__modes) +{ + FILE *ret; + efi_status_t status; + efi_guid_t sfsGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; + efi_simple_file_system_protocol_t *sfs = NULL; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), par, i; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[BUFSIZ]; +#endif + errno = 0; + if(!__filename || !*__filename || !__modes || (__modes[0] != CL('r') && __modes[0] != CL('w') && __modes[0] != CL('a') && + __modes[0] != CL('*')) || (__modes[1] != 0 && __modes[1] != CL('d') && __modes[1] != CL('+'))) { + errno = EINVAL; + return NULL; + } + /* fake some device names. UEFI has no concept of device files */ + if(!strcmp(__filename, CL("/dev/stdin"))) { + if(__modes[0] == CL('w') || __modes[0] == CL('a')) { errno = EPERM; return NULL; } + return stdin; + } + if(!strcmp(__filename, CL("/dev/stdout"))) { + if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } + return stdout; + } + if(!strcmp(__filename, CL("/dev/stderr"))) { + if(__modes[0] == CL('r')) { errno = EPERM; return NULL; } + return stderr; + } + if(!memcmp(__filename, CL("/dev/serial"), 11 * sizeof(char_t))) { + par = (uintn_t)atol(__filename + 11); + if(!__ser) { + efi_guid_t serGuid = EFI_SERIAL_IO_PROTOCOL_GUID; + status = BS->LocateProtocol(&serGuid, NULL, (void**)&__ser); + if(EFI_ERROR(status) || !__ser) { errno = ENOENT; return NULL; } + } + __ser->SetAttributes(__ser, par > 9600 ? par : 115200, 0, 1000, NoParity, 8, OneStopBit); + return (FILE*)__ser; + } + if(!memcmp(__filename, CL("/dev/disk"), 9 * sizeof(char_t))) { + par = (uintn_t)atol(__filename + 9); + if(!__blk_ndevs) { + efi_guid_t bioGuid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_handle_t handles[128]; + uintn_t handle_size = sizeof(handles); + status = BS->LocateHandle(ByProtocol, &bioGuid, NULL, &handle_size, (efi_handle_t*)&handles); + if(!EFI_ERROR(status)) { + handle_size /= (uintn_t)sizeof(efi_handle_t); + /* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */ + if(handle_size < 1) + handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t); + __blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t)); + if(__blk_devs) { + memset(__blk_devs, 0, handle_size * sizeof(block_file_t)); + for(i = __blk_ndevs = 0; i < handle_size; i++) + if(handles[i] && !EFI_ERROR(BS->HandleProtocol(handles[i], &bioGuid, (void **) &__blk_devs[__blk_ndevs].bio)) && + __blk_devs[__blk_ndevs].bio && __blk_devs[__blk_ndevs].bio->Media && + __blk_devs[__blk_ndevs].bio->Media->BlockSize > 0) + __blk_ndevs++; + } else + __blk_ndevs = 0; + } + } + if(__blk_ndevs && par < __blk_ndevs) + return (FILE*)__blk_devs[par].bio; + errno = ENOENT; + return NULL; + } + if(!__root_dir && LIP) { + status = BS->HandleProtocol(LIP->DeviceHandle, &sfsGuid, (void **)&sfs); + if(!EFI_ERROR(status)) + status = sfs->OpenVolume(sfs, &__root_dir); + } + if(!__root_dir) { + errno = ENODEV; + return NULL; + } + ret = (FILE*)malloc(sizeof(FILE)); + if(!ret) return NULL; + /* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create + * also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must + * pass read too. This poses a problem of truncating a write-only file, see issue #26, we have to do that manually */ +#ifndef UEFI_NO_UTF8 + mbstowcs((wchar_t*)&wcname, __filename, BUFSIZ - 1); + status = __root_dir->Open(__root_dir, &ret, (wchar_t*)&wcname, +#else + status = __root_dir->Open(__root_dir, &ret, (wchar_t*)__filename, +#endif + __modes[0] == CL('w') || __modes[0] == CL('a') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE) : + EFI_FILE_MODE_READ | (__modes[0] == CL('*') || __modes[1] == CL('+') ? EFI_FILE_MODE_WRITE : 0), + __modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + free(ret); return NULL; + } + if(__modes[0] == CL('*')) return ret; + status = ret->GetInfo(ret, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) { + ret->Close(ret); free(ret); errno = ENOTDIR; return NULL; + } + if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) { + ret->Close(ret); free(ret); errno = EISDIR; return NULL; + } + if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END); + if(__modes[0] == CL('w')) { + /* manually truncate file size + * See https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.c + * function FileHandleSetSize */ + info.FileSize = 0; + ret->SetInfo(ret, &infGuid, fsiz, &info); + } + return ret; +} + +size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream) +{ + uintn_t bs = __size * __n, i, n; + efi_status_t status; + if(!__ptr || __size < 1 || __n < 1 || !__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + status = __ser->Read(__ser, &bs, __ptr); + } else { + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; + bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; + status = __blk_devs[i].bio->ReadBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, __ptr); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + __blk_devs[i].offset += bs; + return bs / __size; + } + status = __stream->Read(__stream, &bs, __ptr); + } + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + return bs / __size; +} + +size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__stream) +{ + uintn_t bs = __size * __n, n, i; + efi_status_t status; + if(!__ptr || __size < 1 || __n < 1 || !__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + status = __ser->Write(__ser, &bs, (void*)__ptr); + } else { + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + n = __blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize; + bs = (bs / __blk_devs[i].bio->Media->BlockSize) * __blk_devs[i].bio->Media->BlockSize; + status = __blk_devs[i].bio->WriteBlocks(__blk_devs[i].bio, __blk_devs[i].bio->Media->MediaId, n, bs, (void*)__ptr); + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + __blk_devs[i].offset += bs; + return bs / __size; + } + status = __stream->Write(__stream, &bs, (void *)__ptr); + } + if(EFI_ERROR(status)) { + __stdio_seterrno(status); + return 0; + } + return bs / __size; +} + +int fseek (FILE *__stream, long int __off, int __whence) +{ + off_t off = 0; + efi_status_t status; + efi_guid_t infoGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = sizeof(efi_file_info_t), i; + if(!__stream || (__whence != SEEK_SET && __whence != SEEK_CUR && __whence != SEEK_END)) { + errno = EINVAL; + return -1; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return -1; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return -1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + off = (uint64_t)__blk_devs[i].bio->Media->BlockSize * (uint64_t)__blk_devs[i].bio->Media->LastBlock; + switch(__whence) { + case SEEK_END: + __blk_devs[i].offset = off + __off; + break; + case SEEK_CUR: + __blk_devs[i].offset += __off; + break; + case SEEK_SET: + __blk_devs[i].offset = __off; + break; + } + if(__blk_devs[i].offset < 0) __blk_devs[i].offset = 0; + if(__blk_devs[i].offset > off) __blk_devs[i].offset = off; + __blk_devs[i].offset = (__blk_devs[i].offset / __blk_devs[i].bio->Media->BlockSize) * + __blk_devs[i].bio->Media->BlockSize; + return 0; + } + switch(__whence) { + case SEEK_END: + status = __stream->GetInfo(__stream, &infoGuid, &fsiz, &info); + if(!EFI_ERROR(status)) { + off = info.FileSize + __off; + status = __stream->SetPosition(__stream, off); + } + break; + case SEEK_CUR: + status = __stream->GetPosition(__stream, &off); + if(!EFI_ERROR(status)) { + off += __off; + status = __stream->SetPosition(__stream, off); + } + break; + default: + status = __stream->SetPosition(__stream, __off); + break; + } + return EFI_ERROR(status) ? -1 : 0; +} + +long int ftell (FILE *__stream) +{ + uint64_t off = 0; + uintn_t i; + efi_status_t status; + if(!__stream) { + errno = EINVAL; + return -1; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return -1; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return -1; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + return (long int)__blk_devs[i].offset; + } + status = __stream->GetPosition(__stream, &off); + return EFI_ERROR(status) ? -1 : (long int)off; +} + +int feof (FILE *__stream) +{ + uint64_t off = 0; + efi_guid_t infGuid = EFI_FILE_INFO_GUID; + efi_file_info_t info; + uintn_t fsiz = (uintn_t)sizeof(efi_file_info_t), i; + efi_status_t status; + if(!__stream) { + errno = EINVAL; + return 0; + } + if(__stream == stdin || __stream == stdout || __stream == stderr) { + errno = ESPIPE; + return 0; + } + if(__ser && __stream == (FILE*)__ser) { + errno = EBADF; + return 0; + } + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return __blk_devs[i].offset == (off_t)__blk_devs[i].bio->Media->BlockSize * (off_t)__blk_devs[i].bio->Media->LastBlock; + } + status = __stream->GetPosition(__stream, &off); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + return 1; + } + status = __stream->GetInfo(__stream, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + __stream->SetPosition(__stream, off); + return info.FileSize == off; +} + +int vsnprintf(char_t *dst, size_t maxlen, const char_t *fmt, __builtin_va_list args) +{ +#define needsescape(a) (a==CL('\"') || a==CL('\\') || a==CL('\a') || a==CL('\b') || a==CL('\033') || a==CL('\f') || \ + a==CL('\r') || a==CL('\n') || a==CL('\t') || a==CL('\v')) + efi_physical_address_t m; + uint8_t *mem; + int64_t arg; + int len, sign, i, j; + char_t *p, *orig=dst, *end = dst + maxlen - 1, tmpstr[24], pad, n; +#ifdef UEFI_NO_UTF8 + char *c; +#endif + if(dst==NULL || fmt==NULL) + return 0; + + arg = 0; + while(*fmt && dst < end) { + if(*fmt==CL('%')) { + fmt++; + if(*fmt==CL('%')) goto put; + len=0; pad=CL(' '); + if(*fmt==CL('0')) pad=CL('0'); + while(*fmt>=CL('0') && *fmt<=CL('9')) { + len *= 10; + len += *fmt-CL('0'); + fmt++; + } + if(*fmt==CL('l')) fmt++; + if(*fmt==CL('c')) { + arg = __builtin_va_arg(args, uint32_t); +#ifndef UEFI_NO_UTF8 + if(arg<0x80) { *dst++ = arg; } else + if(arg<0x800) { *dst++ = ((arg>>6)&0x1F)|0xC0; *dst++ = (arg&0x3F)|0x80; } else + { *dst++ = ((arg>>12)&0x0F)|0xE0; *dst++ = ((arg>>6)&0x3F)|0x80; *dst++ = (arg&0x3F)|0x80; } +#else + *dst++ = (wchar_t)(arg & 0xffff); +#endif + fmt++; + continue; + } else + if(*fmt==CL('d') || *fmt==CL('i')) { + arg = __builtin_va_arg(args, int64_t); + sign=0; + if(arg<0) { + arg*=-1; + sign++; + } + i=23; + tmpstr[i]=0; + do { + tmpstr[--i]=CL('0')+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]=CL('-'); + } + if(len>0 && len<23) { + while(i && i>23-len) { + tmpstr[--i]=pad; + } + } + p=&tmpstr[i]; + goto copystring; + } else + if(*fmt==CL('p')) { + arg = __builtin_va_arg(args, uint64_t); + len = 16; pad = CL('0'); goto hex; + } else + if(*fmt==CL('x') || *fmt==CL('X')) { + arg = __builtin_va_arg(args, int64_t); +hex: i=16; + tmpstr[i]=0; + do { + n=arg & 0xf; + /* 0-9 => '0'-'9', 10-15 => 'A'-'F' */ + tmpstr[--i]=n+(n>9?(*fmt==CL('X')?0x37:0x57):0x30); + arg>>=4; + } while(arg!=0 && i>0); + /* padding, only leading zeros */ + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]=CL('0'); + } + } + p=&tmpstr[i]; + goto copystring; + } else + if(*fmt==CL('s') || *fmt==CL('q')) { + p = __builtin_va_arg(args, char_t*); +copystring: if(p==NULL) { + p=CL("(null)"); + } + while(*p && dst + 2 < end) { + if(*fmt==CL('q') && needsescape(*p)) { + *dst++ = CL('\\'); + switch(*p) { + case CL('\a'): *dst++ = CL('a'); break; + case CL('\b'): *dst++ = CL('b'); break; + case 27: *dst++ = CL('e'); break; /* gcc 10.2 doesn't like CL('\e') in ansi mode */ + case CL('\f'): *dst++ = CL('f'); break; + case CL('\n'): *dst++ = CL('n'); break; + case CL('\r'): *dst++ = CL('r'); break; + case CL('\t'): *dst++ = CL('t'); break; + case CL('\v'): *dst++ = CL('v'); break; + default: *dst++ = *p++; break; + } + } else { + if(*p == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); + *dst++ = *p++; + } + } + } else +#ifdef UEFI_NO_UTF8 + if(*fmt==L'S' || *fmt==L'Q') { + c = __builtin_va_arg(args, char*); + if(c==NULL) goto copystring; + while(*p && dst + 2 < end) { + arg = *c; + if((*c & 128) != 0) { + if((*c & 32) == 0 ) { + arg = ((*c & 0x1F)<<6)|(*(c+1) & 0x3F); + c += 1; + } else + if((*c & 16) == 0 ) { + arg = ((*c & 0xF)<<12)|((*(c+1) & 0x3F)<<6)|(*(c+2) & 0x3F); + c += 2; + } else + if((*c & 8) == 0 ) { + arg = ((*c & 0x7)<<18)|((*(c+1) & 0x3F)<<12)|((*(c+2) & 0x3F)<<6)|(*(c+3) & 0x3F); + c += 3; + } else + arg = L'?'; + } + if(!arg) break; + if(*fmt==L'Q' && needsescape(arg)) { + *dst++ = L'\\'; + switch(arg) { + case L'\a': *dst++ = L'a'; break; + case L'\b': *dst++ = L'b'; break; + case 27: *dst++ = L'e'; break; /* gcc 10.2 doesn't like L'\e' in ansi mode */ + case L'\f': *dst++ = L'f'; break; + case L'\n': *dst++ = L'n'; break; + case L'\r': *dst++ = L'r'; break; + case L'\t': *dst++ = L't'; break; + case L'\v': *dst++ = L'v'; break; + default: *dst++ = arg; break; + } + } else { + if(arg == L'\n') *dst++ = L'\r'; + *dst++ = (wchar_t)(arg & 0xffff); + } + } + } else +#endif + if(*fmt==CL('D')) { + m = __builtin_va_arg(args, efi_physical_address_t); + for(j = 0; j < (len < 1 ? 1 : (len > 16 ? 16 : len)); j++) { + for(i = 44; i >= 0; i -= 4) { + n = (m >> i) & 15; *dst++ = n + (n>9?0x37:0x30); + if(dst >= end) goto zro; + } + *dst++ = CL(':'); if(dst >= end) goto zro; + *dst++ = CL(' '); if(dst >= end) goto zro; + mem = (uint8_t*)m; + for(i = 0; i < 16; i++) { + n = (mem[i] >> 4) & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; + n = mem[i] & 15; *dst++ = n + (n>9?0x37:0x30); if(dst >= end) goto zro; + *dst++ = CL(' ');if(dst >= end) goto zro; + } + *dst++ = CL(' '); if(dst >= end) goto zro; + for(i = 0; i < 16; i++) { + *dst++ = (mem[i] < 32 || mem[i] >= 127 ? CL('.') : (char_t)mem[i]); + if(dst >= end) goto zro; + } + *dst++ = CL('\r'); if(dst >= end) goto zro; + *dst++ = CL('\n'); if(dst >= end) goto zro; + m += 16; + } + } + } else { +put: if(*fmt == CL('\n') && (orig == dst || *(dst - 1) != CL('\r'))) *dst++ = CL('\r'); + *dst++ = *fmt; + } + fmt++; + } +zro:*dst=0; + return (int)(dst-orig); +#undef needsescape +} + +int vsprintf(char_t *dst, const char_t *fmt, __builtin_va_list args) +{ + return vsnprintf(dst, BUFSIZ, fmt, args); +} + +int sprintf(char_t *dst, const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vsnprintf(dst, BUFSIZ, fmt, args); + __builtin_va_end(args); + return ret; +} + +int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vsnprintf(dst, maxlen, fmt, args); + __builtin_va_end(args); + return ret; +} + +int vprintf(const char_t* fmt, __builtin_va_list args) +{ + int ret; + wchar_t dst[BUFSIZ]; +#ifndef UEFI_NO_UTF8 + char_t tmp[BUFSIZ]; + ret = vsnprintf(tmp, BUFSIZ, fmt, args); + mbstowcs(dst, tmp, BUFSIZ - 1); +#else + ret = vsnprintf(dst, BUFSIZ, fmt, args); +#endif + ST->ConOut->OutputString(ST->ConOut, (wchar_t *)&dst); + return ret; +} + +int printf(const char_t* fmt, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + ret = vprintf(fmt, args); + __builtin_va_end(args); + return ret; +} + +int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args) +{ + wchar_t dst[BUFSIZ]; + char_t tmp[BUFSIZ]; + uintn_t ret, i; +#ifndef UEFI_NO_UTF8 + ret = (uintn_t)vsnprintf(tmp, BUFSIZ, __format, args); + ret = mbstowcs(dst, tmp, BUFSIZ - 1); +#else + ret = vsnprintf(dst, BUFSIZ, __format, args); +#endif + if(ret < 1 || !__stream || __stream == stdin) return 0; + for(i = 0; i < __blk_ndevs; i++) + if(__stream == (FILE*)__blk_devs[i].bio) { + errno = EBADF; + return -1; + } + if(__stream == stdout) + ST->ConOut->OutputString(ST->ConOut, (wchar_t*)&dst); + else if(__stream == stderr) + ST->StdErr->OutputString(ST->StdErr, (wchar_t*)&dst); + else if(__ser && __stream == (FILE*)__ser) { +#ifdef UEFI_NO_UTF8 + wcstombs((char*)&tmp, dst, BUFSIZ - 1); +#endif + __ser->Write(__ser, &ret, (void*)&tmp); + } else +#ifndef UEFI_NO_UTF8 + __stream->Write(__stream, &ret, (void*)&tmp); +#else + __stream->Write(__stream, &ret, (void*)&dst); +#endif + return (int)ret; +} + +int fprintf (FILE *__stream, const char_t *__format, ...) +{ + int ret; + __builtin_va_list args; + __builtin_va_start(args, __format); + ret = vfprintf(__stream, __format, args); + __builtin_va_end(args); + return ret; +} + +int getchar_ifany (void) +{ + efi_input_key_t key = { 0 }; + efi_status_t status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); + return EFI_ERROR(status) ? 0 : key.UnicodeChar; +} + +int getchar (void) +{ + uintn_t idx; + BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx); + return getchar_ifany(); +} + +int putchar (int __c) +{ + wchar_t tmp[2]; + tmp[0] = (wchar_t)__c; + tmp[1] = 0; + ST->ConOut->OutputString(ST->ConOut, (__c == L'\n' ? (wchar_t*)L"\r\n" : (wchar_t*)&tmp)); + return (int)tmp[0]; +} diff --git a/libs/posix-uefi/uefi/stdlib.c b/libs/posix-uefi/uefi/stdlib.c new file mode 100644 index 0000000..81b33df --- /dev/null +++ b/libs/posix-uefi/uefi/stdlib.c @@ -0,0 +1,365 @@ +/* + * stdlib.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 Implementing functions which are defined in stdlib.h + * + */ + +#include + +int errno = 0; +static uint64_t __srand_seed = 6364136223846793005ULL; +extern void __stdio_cleanup(void); +#ifndef UEFI_NO_TRACK_ALLOC +static uintptr_t *__stdlib_allocs = NULL; +static uintn_t __stdlib_numallocs = 0; +#endif + +int atoi(const char_t *s) +{ + return (int)atol(s); +} + +int64_t atol(const char_t *s) +{ + int64_t sign = 1; + if(!s || !*s) return 0; + if(*s == CL('-')) { sign = -1; s++; } + if(s[0] == CL('0')) { + if(s[1] == CL('x')) + return strtol(s + 2, NULL, 16) * sign; + if(s[1] >= CL('0') && s[1] <= CL('7')) + return strtol(s, NULL, 8) * sign; + } + return strtol(s, NULL, 10) * sign; +} + +int64_t strtol (const char_t *s, char_t **__endptr, int __base) +{ + int64_t v=0, sign = 1; + if(!s || !*s) return 0; + if(*s == CL('-')) { sign = -1; s++; } + while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) || + (*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) { + v *= __base; + if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9'))) + v += (*s)-CL('0'); + else if(__base == 16 && *s >= CL('a') && *s <= CL('f')) + v += (*s)-CL('a')+10; + else if(__base == 16 && *s >= CL('A') && *s <= CL('F')) + v += (*s)-CL('A')+10; + s++; + } + if(__endptr) *__endptr = (char_t*)s; + return v * sign; +} + +void *malloc (size_t __size) +{ + void *ret = NULL; + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2); + if(i == __stdlib_numallocs) { + /* no free slots found, (re)allocate the housekeeping array */ + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (__stdlib_numallocs + 2) * sizeof(uintptr_t), &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } + if(__stdlib_allocs) memcpy(ret, __stdlib_allocs, __stdlib_numallocs * sizeof(uintptr_t)); + __stdlib_allocs = (uintptr_t*)ret; + __stdlib_allocs[i] = __stdlib_allocs[i + 1] = 0; + __stdlib_numallocs += 2; + ret = NULL; + } +#endif + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } +#ifndef UEFI_NO_TRACK_ALLOC + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; +#endif + return ret; +} + +void *calloc (size_t __nmemb, size_t __size) +{ + void *ret = malloc(__nmemb * __size); + if(ret) memset(ret, 0, __nmemb * __size); + return ret; +} + +void *realloc (void *__ptr, size_t __size) +{ + void *ret = NULL; + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; +#endif + if(!__ptr) return malloc(__size); + if(!__size) { free(__ptr); return NULL; } +#ifndef UEFI_NO_TRACK_ALLOC + /* get the slot which stores the old size for this buffer */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); + if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; } + /* allocate a new buffer and copy data from old buffer */ + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } + else { + memcpy(ret, (void*)__stdlib_allocs[i], __stdlib_allocs[i + 1] < __size ? __stdlib_allocs[i + 1] : __size); + if(__size > __stdlib_allocs[i + 1]) memset((uint8_t*)ret + __stdlib_allocs[i + 1], 0, __size - __stdlib_allocs[i + 1]); + /* free old buffer and store new buffer in slot */ + BS->FreePool((void*)__stdlib_allocs[i]); + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; + } +#else + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; } + /* this means out of bounds read, but fine with POSIX as the end of new buffer supposed to be left uninitialized) */ + memcpy(ret, (void*)__ptr, __size); + BS->FreePool((void*)__ptr); +#endif + return ret; +} + +void free (void *__ptr) +{ + efi_status_t status; +#ifndef UEFI_NO_TRACK_ALLOC + uintn_t i; +#endif + if(!__ptr) { errno = ENOMEM; return; } +#ifndef UEFI_NO_TRACK_ALLOC + /* find and clear the slot */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); + if(i == __stdlib_numallocs) { errno = ENOMEM; return; } + __stdlib_allocs[i] = 0; + __stdlib_allocs[i + 1] = 0; + /* if there are only empty slots, free the housekeeping array too */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] == 0; i += 2); + if(i == __stdlib_numallocs) { BS->FreePool(__stdlib_allocs); __stdlib_allocs = NULL; __stdlib_numallocs = 0; } +#endif + status = BS->FreePool(__ptr); + if(EFI_ERROR(status)) errno = ENOMEM; +} + +void abort () +{ +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + BS->Exit(IM, EFI_ABORTED, 0, NULL); +} + +void exit (int __status) +{ +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL); +} + +int exit_bs() +{ + efi_status_t status = 0; + efi_memory_descriptor_t *memory_map = NULL; + uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0; +#ifndef UEFI_NO_TRACK_ALLOC + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_allocs = NULL; + __stdlib_numallocs = 0; +#endif + __stdio_cleanup(); + while(cnt--) { + status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL); + if (status!=EFI_BUFFER_TOO_SMALL) break; + status = BS->ExitBootServices(IM, map_key); + if(!EFI_ERROR(status)) return 0; + } + return (int)(status & 0xffff); +} + +void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp) +{ + uint64_t s=0, e=nmemb, m; + int ret; + while (s < e) { + m = s + (e-s)/2; + ret = cmp(key, (uint8_t*)base + m*size); + if (ret < 0) e = m; else + if (ret > 0) s = m+1; else + return (void *)((uint8_t*)base + m*size); + } + return NULL; +} + +int mblen(const char *s, size_t n) +{ + const char *e = s+n; + int c = 0; + if(s) { + while(s < e && *s) { + if((*s & 128) != 0) { + if((*s & 32) == 0 ) s++; else + if((*s & 16) == 0 ) s+=2; else + if((*s & 8) == 0 ) s+=3; + } + c++; + s++; + } + } + return c; +} + +int mbtowc (wchar_t * __pwc, const char *s, size_t n) +{ + wchar_t arg; + int ret = 1; + if(!s || !*s) return 0; + arg = (wchar_t)*s; + if((*s & 128) != 0) { + if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else + if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else + if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; } + else return -1; + } + if(__pwc) *__pwc = arg; + return ret; +} + +int wctomb (char *s, wchar_t u) +{ + int ret = 0; + if(u<0x80) { + *s = u; + ret = 1; + } else if(u<0x800) { + *(s+0)=((u>>6)&0x1F)|0xC0; + *(s+1)=(u&0x3F)|0x80; + ret = 2; + } else { + *(s+0)=((u>>12)&0x0F)|0xE0; + *(s+1)=((u>>6)&0x3F)|0x80; + *(s+2)=(u&0x3F)|0x80; + ret = 3; + } + return ret; +} + +size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n) +{ + int r; + wchar_t *orig = __pwcs; + if(!__s || !*__s) return 0; + while(*__s) { + r = mbtowc(__pwcs, __s, __n - (size_t)(__pwcs - orig)); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__pwcs = 0; + return (size_t)(__pwcs - orig); +} + +size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n) +{ + int r; + char *orig = __s; + if(!__s || !__pwcs || !*__pwcs) return 0; + while(*__pwcs && ((size_t)(__s - orig + 4) < __n)) { + r = wctomb(__s, *__pwcs); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__s = 0; + return (size_t)(__s - orig); +} + +void srand(unsigned int __seed) +{ + __srand_seed = __seed - 1; +} + +int rand() +{ + efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID; + efi_rng_protocol_t *rng = NULL; + efi_status_t status; + int ret = 0; + + __srand_seed = 6364136223846793005ULL*__srand_seed + 1; + status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng); + if(!EFI_ERROR(status) && rng) + rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret); + ret ^= (int)(__srand_seed>>33); + return ret; +} + +uint8_t *getenv(char_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; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[256]; + mbstowcs((wchar_t*)&wcname, name, 256); + status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp); +#else + status = RT->GetVariable(name, &globGuid, &attr, len, &tmp); +#endif + 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(char_t *name, uintn_t len, uint8_t *data) +{ + efi_guid_t globGuid = EFI_GLOBAL_VARIABLE; + efi_status_t status; +#ifndef UEFI_NO_UTF8 + wchar_t wcname[256]; + mbstowcs((wchar_t*)&wcname, name, 256); + status = RT->SetVariable(wcname, &globGuid, 0, len, data); +#else + status = RT->SetVariable(name, &globGuid, 0, len, data); +#endif + return !EFI_ERROR(status); +} diff --git a/libs/posix-uefi/uefi/string.c b/libs/posix-uefi/uefi/string.c new file mode 100644 index 0000000..5a00aa6 --- /dev/null +++ b/libs/posix-uefi/uefi/string.c @@ -0,0 +1,262 @@ +/* + * string.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 Implementing functions which are defined in string.h + * + */ + +#include + +void *memcpy(void *dst, const void *src, size_t n) +{ + uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; + if(src && dst && src != dst && n>0) { + while(n--) *a++ = *b++; + } + return dst; +} + +void *memmove(void *dst, const void *src, size_t n) +{ + uint8_t *a=(uint8_t*)dst,*b=(uint8_t*)src; + if(src && dst && src != dst && n>0) { + if(a>b && a0) *a--=*b--; + } else { + while(n--) *a++ = *b++; + } + } + return dst; +} + +void *memset(void *s, int c, size_t n) +{ + uint8_t *p=(uint8_t*)s; + if(s && n>0) { + while(n--) *p++ = (uint8_t)c; + } + return s; +} + +int memcmp(const void *s1, const void *s2, size_t n) +{ + uint8_t *a=(uint8_t*)s1,*b=(uint8_t*)s2; + if(s1 && s2 && s1 != s2 && n>0) { + while(n--) { + if(*a != *b) return *a - *b; + a++; b++; + } + } + return 0; +} + +void *memchr(const void *s, int c, size_t n) +{ + uint8_t *e, *p=(uint8_t*)s; + if(s && n>0) { + for(e=p+n; p0) { + for(e=p+n; p hl) return NULL; + hl -= nl - 1; + while(hl) { + if(!memcmp(c, needle, nl)) return c; + c++; hl--; + } + return NULL; +} + +void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl) +{ + uint8_t *c = (uint8_t*)haystack; + if(!haystack || !needle || !hl || !nl || nl > hl) return NULL; + hl -= nl; + c += hl; + while(hl) { + if(!memcmp(c, needle, nl)) return c; + c--; hl--; + } + return NULL; +} + +char_t *strcpy(char_t *dst, const char_t *src) +{ + char_t *s = dst; + if(src && dst && src != dst) { + while(*src) {*dst++=*src++;} *dst=0; + } + return s; +} + +char_t *strncpy(char_t *dst, const char_t *src, size_t n) +{ + char_t *s = dst; + const char_t *e = src+n; + if(src && dst && src != dst && n>0) { + while(*src && src0) { + dst += strlen(dst); + while(*src && src0) { + while(s1 + +static struct tm __tm; +time_t __mktime_efi(efi_time_t *t); + +/* from musl */ +static uint64_t __year_to_secs(uint64_t year, int *is_leap) +{ + int y, cycles, centuries, leaps, rem; + + if (year-2ULL <= 136) { + y = (int)year; + leaps = (y-68)>>2; + if (!((y-68)&3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) *is_leap = 0; + return 31536000ULL*(uint64_t)(y-70) + 86400ULL*(uint64_t)leaps; + } + + if (!is_leap) is_leap = &(int){0}; + cycles = (int)((year-100) / 400); + rem = (year-100) % 400; + if (rem < 0) { + cycles--; + rem += 400; + } + if (!rem) { + *is_leap = 1; + centuries = 0; + leaps = 0; + } else { + if (rem >= 200) { + if (rem >= 300) { centuries = 3; rem -= 300; } + else { centuries = 2; rem -= 200; } + } else { + if (rem >= 100) { centuries = 1; rem -= 100; } + else centuries = 0; + } + if (!rem) { + *is_leap = 0; + leaps = 0; + } else { + leaps = rem / 4; + rem %= 4; + *is_leap = !rem; + } + } + + leaps += 97*cycles + 24*centuries - *is_leap; + + return (uint64_t)(year-100) * 31536000ULL + (uint64_t)leaps * 86400ULL + 946684800ULL + 86400ULL; +} + +time_t __mktime_efi(efi_time_t *t) +{ + __tm.tm_year = t->Year + (/* workaround some buggy firmware*/ t->Year > 2000 ? -1900 : 98); + __tm.tm_mon = t->Month - 1; + __tm.tm_mday = t->Day; + __tm.tm_hour = t->Hour; + __tm.tm_min = t->Minute; + __tm.tm_sec = t->Second; + __tm.tm_isdst = t->Daylight; + return mktime(&__tm); +} + +/** + * This isn't POSIX, no arguments. Just returns the current time in struct tm + */ +struct tm *localtime (const time_t *__timer) +{ + efi_time_t t = {0}; + (void)__timer; + ST->RuntimeServices->GetTime(&t, NULL); + __mktime_efi(&t); + return &__tm; +} + +time_t mktime(const struct tm *tm) +{ + static const uint64_t secs_through_month[] = { + 0, 31*86400, 59*86400, 90*86400, + 120*86400, 151*86400, 181*86400, 212*86400, + 243*86400, 273*86400, 304*86400, 334*86400 }; + int is_leap; + uint64_t year = (uint64_t)tm->tm_year, t, adj; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + adj = (uint64_t)month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + t = __year_to_secs(year, &is_leap); + t += secs_through_month[month]; + if (is_leap && month >= 2) t += 86400; + t += 86400ULL * (uint64_t)(tm->tm_mday-1); + t += 3600ULL * (uint64_t)tm->tm_hour; + t += 60ULL * (uint64_t)tm->tm_min; + t += (uint64_t)tm->tm_sec; + return (time_t)t; +} + +time_t time(time_t *__timer) +{ + time_t ret; + efi_time_t t = {0}; + ST->RuntimeServices->GetTime(&t, NULL); + ret = __mktime_efi(&t); + if(__timer) *__timer = ret; + return ret; +} + diff --git a/libs/posix-uefi/uefi/uefi.h b/libs/posix-uefi/uefi/uefi.h new file mode 100644 index 0000000..256a10f --- /dev/null +++ b/libs/posix-uefi/uefi/uefi.h @@ -0,0 +1,1433 @@ +/* + * uefi.h + * https://gitlab.com/bztsrc/posix-uefi + * + * 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 Main (and only) header file + * + */ + +#ifndef _UEFI_H_ +#define _UEFI_H_ + +/*** configuration ***/ +/* #define UEFI_NO_UTF8 */ /* use wchar_t in your application */ +/* #define UEFI_NO_TRACK_ALLOC */ /* do not track allocated buffers' size */ +/*** configuration ends ***/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* get these from the compiler or the efi headers, only define if we have neither */ +#if !defined(_STDINT_H) && !defined(_GCC_STDINT_H) && !defined(_EFI_INCLUDE_) +#define _STDINT_H +typedef char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +#ifndef __clang__ +typedef long int int64_t; +typedef unsigned long int uint64_t; +typedef unsigned long int uintptr_t; +#else +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef unsigned long long uintptr_t; +#endif +#endif +extern char c_assert1[sizeof(uint32_t) == 4 ? 1 : -1]; +extern char c_assert2[sizeof(uint64_t) == 8 ? 1 : -1]; +extern char c_assert3[sizeof(uintptr_t) == 8 ? 1 : -1]; + +#ifndef NULL +#define NULL ((void*)0) +#endif +/*** common defines and typedefs ***/ +typedef int64_t intn_t; +typedef uint8_t boolean_t; +typedef uint16_t wchar_t; +typedef uint64_t uintn_t; +typedef uint64_t size_t; +typedef uint64_t time_t; +typedef uint64_t mode_t; +typedef uint64_t off_t; +typedef uint64_t blkcnt_t; +typedef uint64_t efi_status_t; +typedef uint64_t efi_tpl_t; +typedef uint64_t efi_lba_t; +typedef uint64_t efi_physical_address_t; +typedef uint64_t efi_virtual_address_t; +typedef void *efi_handle_t; +typedef void *efi_event_t; +#ifndef UEFI_NO_UTF8 +typedef char char_t; +#define CL(a) a +extern char *__argvutf8; +#else +typedef wchar_t char_t; +#define CL(a) L ## a +#endif + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} efi_guid_t; + +typedef struct { + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} efi_device_path_t; + +typedef struct { + uint32_t Type; + uint32_t Pad; + efi_physical_address_t PhysicalStart; + efi_virtual_address_t VirtualStart; + uint64_t NumberOfPages; + uint64_t Attribute; +} efi_memory_descriptor_t; + +typedef struct { + uint64_t Signature; + uint32_t Revision; + uint32_t HeaderSize; + uint32_t CRC32; + uint32_t Reserved; +} efi_table_header_t; + +/*** definitions only needed when efi.h (either from EDK II or gnu-efi) is NOT included ***/ + +#ifndef EFI_SPECIFICATION_MAJOR_REVISION + +/* efibind.h */ +#ifndef __WCHAR_TYPE__ +# define __WCHAR_TYPE__ short +#endif +#define EFIERR(a) (0x8000000000000000 | (unsigned int)(a)) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | (unsigned int)(a)) + +#define BAD_POINTER 0xFBFBFBFBFBFBFBFB +#define MAX_ADDRESS 0xFFFFFFFFFFFFFFFF + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((uint64_t)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +#ifndef EFIAPI +# ifdef _MSC_EXTENSIONS +# define EFIAPI __cdecl +# elif defined(HAVE_USE_MS_ABI) +# define EFIAPI __attribute__((ms_abi)) +# else +# define EFIAPI +# endif +#endif + +/* efistdarg.h */ +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_copy(d,s) __builtin_va_copy(d,s) + +/* efierr.h */ +#define EFIWARN(a) (a) +#define EFI_ERROR(a) (((intn_t) a) < 0) +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR EFIERR(1) +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BAD_BUFFER_SIZE EFIERR(4) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_NOT_READY EFIERR(6) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_VOLUME_CORRUPTED EFIERR(10) +#define EFI_VOLUME_FULL EFIERR(11) +#define EFI_NO_MEDIA EFIERR(12) +#define EFI_MEDIA_CHANGED EFIERR(13) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_ACCESS_DENIED EFIERR(15) +#define EFI_NO_RESPONSE EFIERR(16) +#define EFI_NO_MAPPING EFIERR(17) +#define EFI_TIMEOUT EFIERR(18) +#define EFI_NOT_STARTED EFIERR(19) +#define EFI_ALREADY_STARTED EFIERR(20) +#define EFI_ABORTED EFIERR(21) +#define EFI_ICMP_ERROR EFIERR(22) +#define EFI_TFTP_ERROR EFIERR(23) +#define EFI_PROTOCOL_ERROR EFIERR(24) +#define EFI_INCOMPATIBLE_VERSION EFIERR(25) +#define EFI_SECURITY_VIOLATION EFIERR(26) +#define EFI_CRC_ERROR EFIERR(27) +#define EFI_END_OF_MEDIA EFIERR(28) +#define EFI_END_OF_FILE EFIERR(31) +#define EFI_INVALID_LANGUAGE EFIERR(32) +#define EFI_COMPROMISED_DATA EFIERR(33) + +#define EFI_WARN_UNKOWN_GLYPH EFIWARN(1) +#define EFI_WARN_UNKNOWN_GLYPH EFIWARN(1) +#define EFI_WARN_DELETE_FAILURE EFIWARN(2) +#define EFI_WARN_WRITE_FAILURE EFIWARN(3) +#define EFI_WARN_BUFFER_TOO_SMALL EFIWARN(4) + +/* efisetjmp.h */ +#ifdef __x86_64__ +typedef struct { + uint64_t Rbx; + uint64_t Rsp; + uint64_t Rbp; + uint64_t Rdi; + uint64_t Rsi; + uint64_t R12; + uint64_t R13; + uint64_t R14; + uint64_t R15; + uint64_t Rip; + uint64_t MxCsr; + uint8_t XmmBuffer[160]; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +#ifdef __aarch64__ +typedef struct { + uint64_t X19; + uint64_t X20; + uint64_t X21; + uint64_t X22; + uint64_t X23; + uint64_t X24; + uint64_t X25; + uint64_t X26; + uint64_t X27; + uint64_t X28; + uint64_t FP; + uint64_t LR; + uint64_t IP0; + uint64_t reserved; + uint64_t D8; + uint64_t D9; + uint64_t D10; + uint64_t D11; + uint64_t D12; + uint64_t D13; + uint64_t D14; + uint64_t D15; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +#if defined(__riscv) && __riscv_xlen == 64 +typedef struct { + uint64_t pc; + uint64_t sp; + uint64_t regs[12]; + double fp[12]; +} __attribute__((aligned(8))) jmp_buf[1]; +#endif +extern uintn_t setjmp(jmp_buf env) __attribute__((returns_twice)); +extern void longjmp(jmp_buf env, uintn_t value) __attribute__((noreturn)); + +/* efidevp.h */ +#define EFI_DEVICE_PATH_PROTOCOL_GUID { 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_DP_TYPE_MASK 0x7F +#define EFI_DP_TYPE_UNPACKED 0x80 +#define END_DEVICE_PATH_TYPE 0x7f +#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 +#define END_DEVICE_PATH_LENGTH (sizeof(efi_device_path_t)) +#define DP_IS_END_TYPE(a) +#define DP_IS_END_SUBTYPE(a) ( ((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define DevicePathType(a) ( ((a)->Type) & EFI_DP_TYPE_MASK ) +#define DevicePathSubType(a) ( (a)->SubType ) +#define DevicePathNodeLength(a) ( ((a)->Length[0]) | ((a)->Length[1] << 8) ) +#define NextDevicePathNode(a) ( (efi_device_path_t *) ( ((uint8_t *) (a)) + DevicePathNodeLength(a))) +#define IsDevicePathEndType(a) ( DevicePathType(a) == END_DEVICE_PATH_TYPE ) +#define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) +#define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) +#define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED ) +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (uint8_t) (l); \ + (a)->Length[1] = (uint8_t) ((l) >> 8); \ + } +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH_TYPE; \ + (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \ + (a)->Length[0] = sizeof(efi_device_path_t); \ + (a)->Length[1] = 0; \ + } + +/* efiapi.h */ +#define EFI_SPECIFICATION_MAJOR_REVISION 1 +#define EFI_SPECIFICATION_MINOR_REVISION 02 + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 +#define EFI_TPL_APPLICATION TPL_APPLICATION +#define EFI_TPL_CALLBACK TPL_CALLBACK +#define EFI_TPL_NOTIFY TPL_NOTIFY +#define EFI_TPL_HIGH_LEVEL TPL_HIGH_LEVEL + +#define NextMemoryDescriptor(Ptr,Size) ((efi_memory_descriptor_t *) (((uint8_t *) Ptr) + Size)) + +#define EFI_PAGE_SIZE 4096 +#define EFI_PAGE_MASK 0xFFF +#define EFI_PAGE_SHIFT 12 + +#define EFI_SIZE_TO_PAGES(a) ( ((a) >> EFI_PAGE_SHIFT) + ((a) & EFI_PAGE_MASK ? 1 : 0) ) + +#define EFI_MEMORY_UC 0x0000000000000001 +#define EFI_MEMORY_WC 0x0000000000000002 +#define EFI_MEMORY_WT 0x0000000000000004 +#define EFI_MEMORY_WB 0x0000000000000008 +#define EFI_MEMORY_UCE 0x0000000000000010 +#define EFI_MEMORY_WP 0x0000000000001000 +#define EFI_MEMORY_RP 0x0000000000002000 +#define EFI_MEMORY_XP 0x0000000000004000 +#define EFI_MEMORY_RUNTIME 0x8000000000000000 +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_RUNTIME_CONTEXT 0x20000000 + +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 + +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define EVT_EFI_SIGNAL_MASK 0x000000FF +#define EVT_EFI_SIGNAL_MAX 4 + +#define EFI_EVENT_TIMER EVT_TIMER +#define EFI_EVENT_RUNTIME EVT_RUNTIME +#define EFI_EVENT_RUNTIME_CONTEXT EVT_RUNTIME_CONTEXT +#define EFI_EVENT_NOTIFY_WAIT EVT_NOTIFY_WAIT +#define EFI_EVENT_NOTIFY_SIGNAL EVT_NOTIFY_SIGNAL +#define EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES EVT_SIGNAL_EXIT_BOOT_SERVICES +#define EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE +#define EFI_EVENT_EFI_SIGNAL_MASK EVT_EFI_SIGNAL_MASK +#define EFI_EVENT_EFI_SIGNAL_MAX EVT_EFI_SIGNAL_MAX + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020 + +#define EFI_OPTIONAL_PTR 0x00000001 +#define EFI_INTERNAL_FNC 0x00000002 +#define EFI_INTERNAL_PTR 0x00000004 + +#define EFI_GLOBAL_VARIABLE { 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C} } +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 +#define EFI_MAXIMUM_VARIABLE_SIZE 1024 + +#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 +#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 +#define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 + +#define MPS_TABLE_GUID { 0xeb9d2d2f, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ACPI_TABLE_GUID { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define ACPI_20_TABLE_GUID { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81} } +#define SMBIOS_TABLE_GUID { 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } +#define SMBIOS3_TABLE_GUID { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e,0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} } +#define SAL_SYSTEM_TABLE_GUID { 0xeb9d2d32, 0x2d88, 0x11d3, {0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d} } + +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552 +#define EFI_RUNTIME_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 +#define EFI_BOOT_SERVICES_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249 +#define EFI_SYSTEM_TABLE_REVISION (EFI_SPECIFICATION_MAJOR_REVISION<<16) | (EFI_SPECIFICATION_MINOR_REVISION) + +/* eficon.h */ +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID { 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define EFI_BLACK 0x00 +#define EFI_BLUE 0x01 +#define EFI_GREEN 0x02 +#define EFI_CYAN (EFI_BLUE | EFI_GREEN) +#define EFI_RED 0x04 +#define EFI_MAGENTA (EFI_BLUE | EFI_RED) +#define EFI_BROWN (EFI_GREEN | EFI_RED) +#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED) +#define EFI_BRIGHT 0x08 +#define EFI_DARKGRAY (EFI_BRIGHT) +#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT) +#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT) +#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT) +#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT) +#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT) +#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT) +#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT) +#define EFI_TEXT_ATTR(f,b) ((f) | ((b) << 4)) +#define EFI_BACKGROUND_BLACK 0x00 +#define EFI_BACKGROUND_BLUE 0x10 +#define EFI_BACKGROUND_GREEN 0x20 +#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN) +#define EFI_BACKGROUND_RED 0x40 +#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED) +#define BOXDRAW_HORIZONTAL 0x2500 +#define BOXDRAW_VERTICAL 0x2502 +#define BOXDRAW_DOWN_RIGHT 0x250c +#define BOXDRAW_DOWN_LEFT 0x2510 +#define BOXDRAW_UP_RIGHT 0x2514 +#define BOXDRAW_UP_LEFT 0x2518 +#define BOXDRAW_VERTICAL_RIGHT 0x251c +#define BOXDRAW_VERTICAL_LEFT 0x2524 +#define BOXDRAW_DOWN_HORIZONTAL 0x252c +#define BOXDRAW_UP_HORIZONTAL 0x2534 +#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c +#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550 +#define BOXDRAW_DOUBLE_VERTICAL 0x2551 +#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552 +#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553 +#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554 +#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555 +#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556 +#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557 +#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558 +#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559 +#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a +#define BOXDRAW_UP_LEFT_DOUBLE 0x255b +#define BOXDRAW_UP_DOUBLE_LEFT 0x255c +#define BOXDRAW_DOUBLE_UP_LEFT 0x255d +#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e +#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f +#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560 +#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561 +#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562 +#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563 +#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564 +#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565 +#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566 +#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567 +#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568 +#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569 +#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a +#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b +#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c +#define BLOCKELEMENT_FULL_BLOCK 0x2588 +#define BLOCKELEMENT_LIGHT_SHADE 0x2591 +#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2 +#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba +#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc +#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4 +#define ARROW_UP 0x2191 +#define ARROW_DOWN 0x2193 + +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID { 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#define CHAR_NULL 0x0000 +#define CHAR_BACKSPACE 0x0008 +#define CHAR_TAB 0x0009 +#define CHAR_LINEFEED 0x000A +#define CHAR_CARRIAGE_RETURN 0x000D +#define SCAN_NULL 0x0000 +#define SCAN_UP 0x0001 +#define SCAN_DOWN 0x0002 +#define SCAN_RIGHT 0x0003 +#define SCAN_LEFT 0x0004 +#define SCAN_HOME 0x0005 +#define SCAN_END 0x0006 +#define SCAN_INSERT 0x0007 +#define SCAN_DELETE 0x0008 +#define SCAN_PAGE_UP 0x0009 +#define SCAN_PAGE_DOWN 0x000A +#define SCAN_F1 0x000B +#define SCAN_F2 0x000C +#define SCAN_F3 0x000D +#define SCAN_F4 0x000E +#define SCAN_F5 0x000F +#define SCAN_F6 0x0010 +#define SCAN_F7 0x0011 +#define SCAN_F8 0x0012 +#define SCAN_F9 0x0013 +#define SCAN_F10 0x0014 +#define SCAN_F11 0x0015 +#define SCAN_F12 0x0016 +#define SCAN_ESC 0x0017 + +/* efigpt.h */ +#define PRIMARY_PART_HEADER_LBA 1 +#define EFI_PTAB_HEADER_ID "EFI PART" +#define EFI_PART_USED_BY_EFI 0x0000000000000001 +#define EFI_PART_REQUIRED_TO_FUNCTION 0x0000000000000002 +#define EFI_PART_USED_BY_OS 0x0000000000000004 +#define EFI_PART_REQUIRED_BY_OS 0x0000000000000008 +#define EFI_PART_BACKUP_REQUIRED 0x0000000000000010 +#define EFI_PART_USER_DATA 0x0000000000000020 +#define EFI_PART_CRITICAL_USER_DATA 0x0000000000000040 +#define EFI_PART_REDUNDANT_PARTITION 0x0000000000000080 +#define EFI_PART_TYPE_UNUSED_GUID { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} } +#define EFI_PART_TYPE_EFI_SYSTEM_PART_GUID { 0xc12a7328, 0xf81f, 0x11d2, {0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} } +#define EFI_PART_TYPE_LEGACY_MBR_GUID { 0x024dee41, 0x33e7, 0x11d3, {0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f} } + +/* Protocol GUIDs */ +#ifndef INTERNAL_SHELL_GUID +#define INTERNAL_SHELL_GUID { 0xd65a6b8c, 0x71e5, 0x4df0, {0xa9, 0x09, 0xf0, 0xd2, 0x99, 0x2b, 0x5a, 0xa9} } +#endif + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} efi_allocate_type_t; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiUnacceptedMemoryType, + EfiMaxMemoryType +} efi_memory_type_t; + +typedef enum { + TimerCancel, + TimerPeriodic, + TimerRelative, + TimerTypeMax +} efi_timer_delay_t; + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} efi_locate_search_type_t; + +typedef enum { + EfiResetCold, + EfiResetWarm, + EfiResetShutdown +} efi_reset_type_t; + +#else + +#define efi_allocate_type_t EFI_ALLOCATE_TYPE +#define efi_memory_type_t EFI_MEMORY_TYPE +#define efi_timer_delay_t EFI_TIMER_DELAY +#define efi_locate_search_type_t EFI_LOCATE_SEARCH_TYPE +#define efi_reset_type_t EFI_RESET_TYPE + +#endif + +/*** standard input, output and error streams via ConIn, ConOut and StdErr ***/ +typedef struct { + uint16_t ScanCode; + wchar_t UnicodeChar; +} efi_input_key_t; + +typedef efi_status_t (EFIAPI *efi_input_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_input_read_key_t)(void *This, efi_input_key_t *Key); + +typedef struct { + efi_input_reset_t Reset; + efi_input_read_key_t ReadKeyStroke; + efi_event_t WaitForKey; +} simple_input_interface_t; + +typedef efi_status_t (EFIAPI *efi_text_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_text_output_string_t)(void *This, wchar_t *String); +typedef efi_status_t (EFIAPI *efi_text_test_string_t)(void *This, wchar_t *String); +typedef efi_status_t (EFIAPI *efi_text_query_mode_t)(void *This, uintn_t ModeNumber, uintn_t *Column, uintn_t *Row); +typedef efi_status_t (EFIAPI *efi_text_set_mode_t)(void *This, uintn_t ModeNumber); +typedef efi_status_t (EFIAPI *efi_text_set_attribute_t)(void *This, uintn_t Attribute); +typedef efi_status_t (EFIAPI *efi_text_clear_screen_t)(void *This); +typedef efi_status_t (EFIAPI *efi_text_set_cursor_t)(void *This, uintn_t Column, uintn_t Row); +typedef efi_status_t (EFIAPI *efi_text_enable_cursor_t)(void *This, boolean_t Enable); + +typedef struct { + int32_t MaxMode; + int32_t Mode; + int32_t Attribute; + int32_t CursorColumn; + int32_t CursorRow; + boolean_t CursorVisible; +} simple_text_output_mode_t; + +typedef struct { + efi_text_reset_t Reset; + efi_text_output_string_t OutputString; + efi_text_test_string_t TestString; + efi_text_query_mode_t QueryMode; + efi_text_set_mode_t SetMode; + efi_text_set_attribute_t SetAttribute; + efi_text_clear_screen_t ClearScreen; + efi_text_set_cursor_t SetCursorPosition; + efi_text_enable_cursor_t EnableCursor; + simple_text_output_mode_t *Mode; +} simple_text_output_interface_t; + +/*** Runtime Services ***/ +typedef struct { + uint16_t Year; /* 1998 - 2XXX */ + uint8_t Month; /* 1 - 12 */ + uint8_t Day; /* 1 - 31 */ + uint8_t Hour; /* 0 - 23 */ + uint8_t Minute; /* 0 - 59 */ + uint8_t Second; /* 0 - 59 */ + uint8_t Pad1; + uint32_t Nanosecond; /* 0 - 999,999,999 */ + int16_t TimeZone; /* -1440 to 1440 or 2047 */ + uint8_t Daylight; + uint8_t Pad2; +} efi_time_t; + +typedef struct { + uint32_t Resolution; + uint32_t Accuracy; + boolean_t SetsToZero; +} efi_time_capabilities_t; + +typedef struct { + efi_guid_t CapsuleGuid; + uint32_t HeaderSize; + uint32_t Flags; + uint32_t CapsuleImageSize; +} efi_capsule_header_t; + +#ifndef DataBlock +#define DataBlock ContinuationPointer +#endif +typedef struct { + uint64_t Length; + efi_physical_address_t ContinuationPointer; +} efi_capsule_block_descriptor_t; + +typedef efi_status_t (EFIAPI *efi_get_time_t)(efi_time_t *Time, efi_time_capabilities_t *Capabilities); +typedef efi_status_t (EFIAPI *efi_set_time_t)(efi_time_t *Time); +typedef efi_status_t (EFIAPI *efi_get_wakeup_time_t)(boolean_t *Enable, boolean_t *Pending, efi_time_t *Time); +typedef efi_status_t (EFIAPI *efi_set_wakeup_time_t)(boolean_t Enable, efi_time_t *Time); +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); +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, uint32_t *Attributes, + uintn_t *DataSize, void *Data); +typedef efi_status_t (EFIAPI *efi_get_next_variable_name_t)(uintn_t *VariableNameSize, wchar_t *VariableName, + efi_guid_t *VendorGuid); +typedef efi_status_t (EFIAPI *efi_set_variable_t)(wchar_t *VariableName, efi_guid_t *VendorGuid, uint32_t Attributes, + uintn_t DataSize, void *Data); +typedef efi_status_t (EFIAPI *efi_get_next_high_mono_t)(uint64_t *Count); +typedef efi_status_t (EFIAPI *efi_reset_system_t)(efi_reset_type_t ResetType, efi_status_t ResetStatus, uintn_t DataSize, + wchar_t *ResetData); +typedef efi_status_t (EFIAPI *efi_update_capsule_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, + efi_physical_address_t ScatterGatherList); +typedef efi_status_t (EFIAPI *efi_query_capsule_capabilities_t)(efi_capsule_header_t **CapsuleHeaderArray, uintn_t CapsuleCount, + uint64_t *MaximumCapsuleSize, efi_reset_type_t *ResetType); +typedef efi_status_t (EFIAPI *efi_query_variable_info_t)(uint32_t Attributes, uint64_t *MaximumVariableStorageSize, + uint64_t *RemainingVariableStorageSize, uint64_t *MaximumVariableSize); + +typedef struct { + efi_table_header_t Hdr; + + efi_get_time_t GetTime; + efi_set_time_t SetTime; + efi_get_wakeup_time_t GetWakeupTime; + efi_set_wakeup_time_t SetWakeupTime; + + efi_set_virtual_address_map_t SetVirtualAddressMap; + efi_convert_pointer_t ConvertPointer; + + efi_get_variable_t GetVariable; + efi_get_next_variable_name_t GetNextVariableName; + efi_set_variable_t SetVariable; + + efi_get_next_high_mono_t GetNextHighMonotonicCount; + efi_reset_system_t ResetSystem; + + efi_update_capsule_t UpdateCapsule; + efi_query_capsule_capabilities_t QueryCapsuleCapabilities; + efi_query_variable_info_t QueryVariableInfo; +} efi_runtime_services_t; +extern efi_runtime_services_t *RT; +#define gRT RT + +/** Boot Services ***/ +typedef struct { + efi_handle_t AgentHandle; + efi_handle_t ControllerHandle; + uint32_t Attributes; + uint32_t OpenCount; +} efi_open_protocol_information_entry_t; + +typedef efi_tpl_t (EFIAPI *efi_raise_tpl_t)(efi_tpl_t NewTpl); +typedef efi_tpl_t (EFIAPI *efi_restore_tpl_t)(efi_tpl_t OldTpl); +typedef efi_status_t (EFIAPI *efi_allocate_pages_t)(efi_allocate_type_t Type, efi_memory_type_t MemoryType, + uintn_t NoPages, efi_physical_address_t *Memory); +typedef efi_status_t (EFIAPI *efi_free_pages_t)(efi_physical_address_t Memory, uintn_t NoPages); +typedef efi_status_t (EFIAPI *efi_get_memory_map_t)(uintn_t *MemoryMapSize, efi_memory_descriptor_t *MemoryMap, + uintn_t *MapKey, uintn_t *DescriptorSize, uint32_t *DescriptorVersion); +typedef efi_status_t (EFIAPI *efi_allocate_pool_t)(efi_memory_type_t PoolType, uintn_t Size, void **Buffer); +typedef efi_status_t (EFIAPI *efi_free_pool_t)(void *Buffer); +typedef void (EFIAPI *efi_event_notify_t)(efi_event_t Event, void *Context); +typedef efi_status_t (EFIAPI *efi_create_event_t)(uint32_t Type, efi_tpl_t NotifyTpl, efi_event_notify_t NotifyFunction, + void *NextContext, efi_event_t *Event); +typedef efi_status_t (EFIAPI *efi_set_timer_t)(efi_event_t Event, efi_timer_delay_t Type, uint64_t TriggerTime); +typedef efi_status_t (EFIAPI *efi_wait_for_event_t)(uintn_t NumberOfEvents, efi_event_t *Event, uintn_t *Index); +typedef efi_status_t (EFIAPI *efi_signal_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_close_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_check_event_t)(efi_event_t Event); +typedef efi_status_t (EFIAPI *efi_handle_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface); +typedef efi_status_t (EFIAPI *efi_register_protocol_notify_t)(efi_guid_t *Protocol, efi_event_t Event, void **Registration); +typedef efi_status_t (EFIAPI *efi_locate_handle_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, + void *SearchKey, uintn_t *BufferSize, efi_handle_t *Buffer); +typedef efi_status_t (EFIAPI *efi_locate_device_path_t)(efi_guid_t *Protocol, efi_device_path_t **DevicePath, + efi_handle_t *Device); +typedef efi_status_t (EFIAPI *efi_install_configuration_table_t)(efi_guid_t *Guid, void *Table); +typedef efi_status_t (EFIAPI *efi_image_load_t)(boolean_t BootPolicy, efi_handle_t ParentImageHandle, efi_device_path_t *FilePath, + void *SourceBuffer, uintn_t SourceSize, efi_handle_t *ImageHandle); +typedef efi_status_t (EFIAPI *efi_image_start_t)(efi_handle_t ImageHandle, uintn_t *ExitDataSize, wchar_t **ExitData); +typedef efi_status_t (EFIAPI *efi_exit_t)(efi_handle_t ImageHandle, efi_status_t ExitStatus, uintn_t ExitDataSize, + wchar_t *ExitData); +typedef efi_status_t (EFIAPI *efi_exit_boot_services_t)(efi_handle_t ImageHandle, uintn_t MapKey); +typedef efi_status_t (EFIAPI *efi_get_next_monotonic_t)(uint64_t *Count); +typedef efi_status_t (EFIAPI *efi_stall_t)(uintn_t Microseconds); +typedef efi_status_t (EFIAPI *efi_set_watchdog_timer_t)(uintn_t Timeout, uint64_t WatchdogCode, uintn_t DataSize, + wchar_t *WatchdogData); +typedef efi_status_t (EFIAPI *efi_connect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t *DriverImageHandle, + efi_device_path_t *RemainingDevicePath, boolean_t Recursive); +typedef efi_status_t (EFIAPI *efi_disconnect_controller_t)(efi_handle_t ControllerHandle, efi_handle_t DriverImageHandle, + efi_handle_t ChildHandle); +typedef efi_status_t (EFIAPI *efi_open_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, void **Interface, + efi_handle_t AgentHandle, efi_handle_t ControllerHandle, uint32_t Attributes); +typedef efi_status_t (EFIAPI *efi_close_protocol_t)(efi_handle_t Handle, efi_guid_t *Protocol, efi_handle_t AgentHandle, + efi_handle_t ControllerHandle); +typedef efi_status_t (EFIAPI *efi_open_protocol_information_t)(efi_handle_t Handle, efi_guid_t *Protocol, + efi_open_protocol_information_entry_t**EntryBuffer, uintn_t *EntryCount); +typedef efi_status_t (EFIAPI *efi_protocols_per_handle_t)(efi_handle_t Handle, efi_guid_t ***ProtocolBuffer, + uintn_t *ProtocolBufferCount); +typedef efi_status_t (EFIAPI *efi_locate_handle_buffer_t)(efi_locate_search_type_t SearchType, efi_guid_t *Protocol, + void *SearchKey, uintn_t *NoHandles, efi_handle_t **Handles); +typedef efi_status_t (EFIAPI *efi_locate_protocol_t)(efi_guid_t *Protocol, void *Registration, void **Interface); +typedef efi_status_t (EFIAPI *efi_calculate_crc32_t)(void *Data, uintn_t DataSize, uint32_t *Crc32); + +typedef struct { + efi_table_header_t Hdr; + + efi_raise_tpl_t RaiseTPL; + efi_restore_tpl_t RestoreTPL; + + efi_allocate_pages_t AllocatePages; + efi_free_pages_t FreePages; + efi_get_memory_map_t GetMemoryMap; + efi_allocate_pool_t AllocatePool; + efi_free_pool_t FreePool; + + efi_create_event_t CreateEvent; + efi_set_timer_t SetTimer; + efi_wait_for_event_t WaitForEvent; + efi_signal_event_t SignalEvent; + efi_close_event_t CloseEvent; + efi_check_event_t CheckEvent; + + void* InstallProtocolInterface; /* not defined yet */ + void* ReinstallProtocolInterface; + void* UninstallProtocolInterface; + efi_handle_protocol_t HandleProtocol; + efi_handle_protocol_t PCHandleProtocol; + efi_register_protocol_notify_t RegisterProtocolNotify; + efi_locate_handle_t LocateHandle; + efi_locate_device_path_t LocateDevicePath; + efi_install_configuration_table_t InstallConfigurationTable; + + efi_image_load_t LoadImage; + efi_image_start_t StartImage; + efi_exit_t Exit; + void* UnloadImage; /* not defined in gnu-efi either */ + efi_exit_boot_services_t ExitBootServices; + + efi_get_next_monotonic_t GetNextHighMonotonicCount; + efi_stall_t Stall; + efi_set_watchdog_timer_t SetWatchdogTimer; + + efi_connect_controller_t ConnectController; + efi_disconnect_controller_t DisconnectController; + + efi_open_protocol_t OpenProtocol; + efi_close_protocol_t CloseProtocol; + efi_open_protocol_information_t OpenProtocolInformation; + + efi_protocols_per_handle_t ProtocolsPerHandle; + efi_locate_handle_buffer_t LocateHandleBuffer; + efi_locate_protocol_t LocateProtocol; + void* InstallMultipleProtocolInterfaces; + void* UninstallMultipleProtocolInterfaces; + + efi_calculate_crc32_t CalculateCrc32; +} efi_boot_services_t; +extern efi_boot_services_t *BS; +#define gBS BS + +/*** Loaded Image Protocol ***/ +#ifndef EFI_LOADED_IMAGE_PROTOCOL_GUID +#define EFI_LOADED_IMAGE_PROTOCOL_GUID { 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B} } +#define LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE_PROTOCOL_GUID + +#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 +#define EFI_IMAGE_INFORMATION_REVISION EFI_LOADED_IMAGE_PROTOCOL_REVISION +#endif + +typedef struct { + uint32_t Revision; + efi_handle_t ParentHandle; + void *SystemTable; + efi_handle_t DeviceHandle; + efi_device_path_t *FilePath; + void *Reserved; + uint32_t LoadOptionsSize; + void *LoadOptions; + void *ImageBase; + uint64_t ImageSize; + efi_memory_type_t ImageCodeType; + efi_memory_type_t ImageDataType; +} efi_loaded_image_protocol_t; +extern efi_loaded_image_protocol_t *LIP; +extern efi_handle_t IM; + +/*** System Table ***/ +typedef struct { + efi_guid_t VendorGuid; + void *VendorTable; +} efi_configuration_table_t; + +typedef struct { + efi_table_header_t Hdr; + + wchar_t *FirmwareVendor; + uint32_t FirmwareRevision; + + efi_handle_t ConsoleInHandle; + simple_input_interface_t *ConIn; + + efi_handle_t ConsoleOutHandle; + simple_text_output_interface_t *ConOut; + + efi_handle_t ConsoleErrorHandle; + simple_text_output_interface_t *StdErr; + + efi_runtime_services_t *RuntimeServices; + efi_boot_services_t *BootServices; + + uintn_t NumberOfTableEntries; + efi_configuration_table_t *ConfigurationTable; +} efi_system_table_t; +extern efi_system_table_t *ST; +#define gST ST + +/*** Simple File System Protocol ***/ +#ifndef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID { 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_IO_INTERFACE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION + +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +#define EFI_FILE_READ_ONLY 0x0000000000000001 +#define EFI_FILE_HIDDEN 0x0000000000000002 +#define EFI_FILE_SYSTEM 0x0000000000000004 +#define EFI_FILE_RESERVED 0x0000000000000008 +#define EFI_FILE_DIRECTORY 0x0000000000000010 +#define EFI_FILE_ARCHIVE 0x0000000000000020 +#define EFI_FILE_VALID_ATTR 0x0000000000000037 + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_HANDLE_REVISION EFI_FILE_PROTOCOL_REVISION +#endif + +#ifndef EFI_FILE_INFO_GUID +#define EFI_FILE_INFO_GUID { 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#endif + +#ifndef FILENAME_MAX +#define FILENAME_MAX 262 /* from FAT spec */ +#endif + +typedef struct { + uint64_t Size; + uint64_t FileSize; + uint64_t PhysicalSize; + efi_time_t CreateTime; + efi_time_t LastAccessTime; + efi_time_t ModificationTime; + uint64_t Attribute; + wchar_t FileName[FILENAME_MAX]; +} efi_file_info_t; + +typedef struct efi_file_handle_s efi_file_handle_t; + +typedef efi_status_t (EFIAPI *efi_volume_open_t)(void *This, efi_file_handle_t **Root); +typedef struct { + uint64_t Revision; + efi_volume_open_t OpenVolume; +} efi_simple_file_system_protocol_t; + +typedef efi_status_t (EFIAPI *efi_file_open_t)(efi_file_handle_t *File, efi_file_handle_t **NewHandle, wchar_t *FileName, + uint64_t OpenMode, uint64_t Attributes); +typedef efi_status_t (EFIAPI *efi_file_close_t)(efi_file_handle_t *File); +typedef efi_status_t (EFIAPI *efi_file_delete_t)(efi_file_handle_t *File); +typedef efi_status_t (EFIAPI *efi_file_read_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_write_t)(efi_file_handle_t *File, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_get_pos_t)(efi_file_handle_t *File, uint64_t *Position); +typedef efi_status_t (EFIAPI *efi_file_set_pos_t)(efi_file_handle_t *File, uint64_t Position); +typedef efi_status_t (EFIAPI *efi_file_get_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t *BufferSize, + void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_set_info_t)(efi_file_handle_t *File, efi_guid_t *InformationType, uintn_t BufferSize, + void *Buffer); +typedef efi_status_t (EFIAPI *efi_file_flush_t)(efi_file_handle_t *File); + +struct efi_file_handle_s { + uint64_t Revision; + efi_file_open_t Open; + efi_file_close_t Close; + efi_file_delete_t Delete; + efi_file_read_t Read; + efi_file_write_t Write; + efi_file_get_pos_t GetPosition; + efi_file_set_pos_t SetPosition; + efi_file_get_info_t GetInfo; + efi_file_set_info_t SetInfo; + efi_file_flush_t Flush; +}; + +/*** Shell Parameter Protocols ***/ +#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID +#define EFI_SHELL_PARAMETERS_PROTOCOL_GUID { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca} } +#endif + +typedef struct { + wchar_t **Argv; + uintn_t Argc; + efi_handle_t StdIn; + efi_handle_t StdOut; + efi_handle_t StdErr; +} efi_shell_parameters_protocol_t; + +#ifndef SHELL_INTERFACE_PROTOCOL_GUID +#define SHELL_INTERFACE_PROTOCOL_GUID { 0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } +#endif + +typedef struct { + efi_handle_t ImageHandle; + void* *Info; + wchar_t **Argv; + uintn_t Argc; + wchar_t **RedirArgv; + uintn_t RedirArgc; + efi_handle_t StdIn; + efi_handle_t StdOut; + efi_handle_t StdErr; +} efi_shell_interface_protocol_t; + +/*** Random Number Generator ***/ +#ifndef EFI_RNG_PROTOCOL_GUID +#define EFI_RNG_PROTOCOL_GUID { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} } +#endif + +typedef efi_status_t (EFIAPI *efi_rng_get_info_t)(void *This, uintn_t *RNGAlgorithmListSize, efi_guid_t *RNGAlgorithmList); +typedef efi_status_t (EFIAPI *efi_rng_get_rng_t)(void *This, efi_guid_t *RNGAlgorithm, uintn_t RNGValueLength, uint8_t *RNGValue); + +typedef struct { + efi_rng_get_info_t GetInfo; + efi_rng_get_rng_t GetRNG; +} efi_rng_protocol_t; + +/*** Serial IO Protocol ***/ +#ifndef EFI_SERIAL_IO_PROTOCOL_GUID +#define EFI_SERIAL_IO_PROTOCOL_GUID { 0xBB25CF6F, 0xF1D4, 0x11D2, {0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD} } + +#define SERIAL_IO_INTERFACE_REVISION 0x00010000 +#define EFI_SERIAL_CLEAR_TO_SEND 0x0010 +#define EFI_SERIAL_DATA_SET_READY 0x0020 +#define EFI_SERIAL_RING_INDICATE 0x0040 +#define EFI_SERIAL_CARRIER_DETECT 0x0080 +#define EFI_SERIAL_REQUEST_TO_SEND 0x0002 +#define EFI_SERIAL_DATA_TERMINAL_READY 0x0001 +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x0100 +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x0200 +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x1000 +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x2000 +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x4000 + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} efi_parity_type_t; + +typedef enum { + DefaultStopBits, + OneStopBit, + OneFiveStopBits, + TwoStopBits +} efi_stop_bits_type_t; + +#else + +#define efi_parity_type_t EFI_PARITY_TYPE +#define efi_stop_bits_type_t EFI_STOP_BITS_TYPE + +#endif + +typedef struct { + uint32_t ControlMask; + uint32_t Timeout; + uint64_t BaudRate; + uint32_t ReceiveFifoDepth; + uint32_t DataBits; + uint32_t Parity; + uint32_t StopBits; +} efi_serial_io_mode_t; + +typedef efi_status_t (EFIAPI *efi_serial_reset_t)(void *This); +typedef efi_status_t (EFIAPI *efi_serial_set_attributes_t)(void *This, uint64_t BaudRate, uint32_t ReceiveFifoDepth, + uint32_t Timeout, efi_parity_type_t Parity, uint8_t DataBits, efi_stop_bits_type_t StopBits); +typedef efi_status_t (EFIAPI *efi_serial_set_control_bits_t)(void *This, uint32_t Control); +typedef efi_status_t (EFIAPI *efi_serial_get_control_bits_t)(void *This, uint32_t *Control); +typedef efi_status_t (EFIAPI *efi_serial_write_t)(void *This, uintn_t *BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_serial_read_t)(void *This, uintn_t *BufferSize, void *Buffer); + +typedef struct { + uint32_t Revision; + efi_serial_reset_t Reset; + efi_serial_set_attributes_t SetAttributes; + efi_serial_set_control_bits_t SetControl; + efi_serial_get_control_bits_t GetControl; + efi_serial_write_t Write; + efi_serial_read_t Read; + efi_serial_io_mode_t *Mode; +} efi_serial_io_protocol_t; + +/*** Block IO Protocol ***/ +#ifndef EFI_BLOCK_IO_PROTOCOL_GUID +#define EFI_BLOCK_IO_PROTOCOL_GUID { 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} } + +#define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 +#define EFI_BLOCK_IO_INTERFACE_REVISION EFI_BLOCK_IO_PROTOCOL_REVISION + +#endif + +typedef struct { + uint32_t MediaId; + boolean_t RemovableMedia; + boolean_t MediaPresent; + boolean_t LogicalPartition; + boolean_t ReadOnly; + boolean_t WriteCaching; + uint32_t BlockSize; + uint32_t IoAlign; + efi_lba_t LastBlock; +} efi_block_io_media_t; + +typedef efi_status_t (EFIAPI *efi_block_reset_t)(void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_block_read_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_block_write_t)(void *This, uint32_t MediaId, efi_lba_t LBA, uintn_t BufferSize, void *Buffer); +typedef efi_status_t (EFIAPI *efi_block_flush_t)(void *This); + +typedef struct { + uint64_t Revision; + efi_block_io_media_t *Media; + efi_block_reset_t Reset; + efi_block_read_t ReadBlocks; + efi_block_write_t WriteBlocks; + efi_block_flush_t FlushBlocks; +} efi_block_io_t; + +typedef struct { + off_t offset; + efi_block_io_t *bio; +} block_file_t; + +/*** Graphics Output Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID { 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } } + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax +} efi_gop_pixel_format_t; + +typedef enum { + EfiBltVideoFill, + EfiBltVideoToBltBuffer, + EfiBltBufferToVideo, + EfiBltVideoToVideo, + EfiGraphicsOutputBltOperationMax +} efi_gop_blt_operation_t; + +#else + +#define efi_gop_pixel_format_t EFI_GRAPHICS_PIXEL_FORMAT +#define efi_gop_blt_operation_t EFI_GRAPHICS_OUTPUT_BLT_OPERATION + +#endif + +typedef struct { + uint32_t RedMask; + uint32_t GreenMask; + uint32_t BlueMask; + uint32_t ReservedMask; +} efi_gop_pixel_bitmask_t; + +typedef struct { + uint32_t Version; + uint32_t HorizontalResolution; + uint32_t VerticalResolution; + efi_gop_pixel_format_t PixelFormat; + efi_gop_pixel_bitmask_t PixelInformation; + uint32_t PixelsPerScanLine; +} efi_gop_mode_info_t; + +typedef struct { + uint32_t MaxMode; + uint32_t Mode; + efi_gop_mode_info_t *Information; + uintn_t SizeOfInfo; + efi_physical_address_t FrameBufferBase; + uintn_t FrameBufferSize; +} efi_gop_mode_t; + +typedef efi_status_t (EFIAPI *efi_gop_query_mode_t)(void *This, uint32_t ModeNumber, uintn_t *SizeOfInfo, + efi_gop_mode_info_t **Info); +typedef efi_status_t (EFIAPI *efi_gop_set_mode_t)(void *This, uint32_t ModeNumber); +typedef efi_status_t (EFIAPI *efi_gop_blt_t)(void *This, uint32_t *BltBuffer, efi_gop_blt_operation_t BltOperation, + uintn_t SourceX, uintn_t SourceY, uintn_t DestinationX, uintn_t DestionationY, uintn_t Width, uintn_t Height, uintn_t Delta); + +typedef struct { + efi_gop_query_mode_t QueryMode; + efi_gop_set_mode_t SetMode; + efi_gop_blt_t Blt; + efi_gop_mode_t *Mode; +} efi_gop_t; + +/*** Simple Pointer Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_SIMPLE_POINTER_PROTOCOL_GUID +#define EFI_SIMPLE_POINTER_PROTOCOL_GUID { 0x31878c87, 0xb75, 0x11d5, { 0x9a, 0x4f, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } } +#endif + +typedef struct { + int32_t RelativeMovementX; + int32_t RelativeMovementY; + int32_t RelativeMovementZ; + boolean_t LeftButton; + boolean_t RightButton; +} efi_simple_pointer_state_t; + +typedef struct { + uint64_t ResolutionX; + uint64_t ResolutionY; + uint64_t ResolutionZ; + boolean_t LeftButton; + boolean_t RightButton; +} efi_simple_pointer_mode_t; + +typedef efi_status_t (EFIAPI *efi_simple_pointer_reset_t) (void *This, boolean_t ExtendedVerification); +typedef efi_status_t (EFIAPI *efi_simple_pointer_get_state_t) (void *This, efi_simple_pointer_state_t *State); + +typedef struct { + efi_simple_pointer_reset_t Reset; + efi_simple_pointer_get_state_t GetState; + efi_event_t WaitForInput; + efi_simple_pointer_mode_t *Mode; +} efi_simple_pointer_protocol_t; + +/*** Option ROM Protocol (not used, but could be useful to have) ***/ +#ifndef EFI_PCI_OPTION_ROM_TABLE_GUID +#define EFI_PCI_OPTION_ROM_TABLE_GUID { 0x7462660f, 0x1cbd, 0x48da, {0xad, 0x11, 0x91, 0x71, 0x79, 0x13, 0x83, 0x1c} } +#endif + +typedef struct { + efi_physical_address_t RomAddress; + efi_memory_type_t MemoryType; + uint32_t RomLength; + uint32_t Seg; + uint8_t Bus; + uint8_t Dev; + uint8_t Func; + boolean_t ExecutedLegacyBiosImage; + boolean_t DontLoadEfiRom; +} efi_pci_option_rom_descriptor_t; + +typedef struct { + uint64_t PciOptionRomCount; + efi_pci_option_rom_descriptor_t *PciOptionRomDescriptors; +} efi_pci_option_rom_table_t; + +/*** GPT partitioning table (not used, but could be useful to have) ***/ +typedef struct { + efi_table_header_t Header; + efi_lba_t MyLBA; + efi_lba_t AlternateLBA; + efi_lba_t FirstUsableLBA; + efi_lba_t LastUsableLBA; + efi_guid_t DiskGUID; + efi_lba_t PartitionEntryLBA; + uint32_t NumberOfPartitionEntries; + uint32_t SizeOfPartitionEntry; + uint32_t PartitionEntryArrayCRC32; +} efi_partition_table_header_t; + +typedef struct { + efi_guid_t PartitionTypeGUID; + efi_guid_t UniquePartitionGUID; + efi_lba_t StartingLBA; + efi_lba_t EndingLBA; + uint64_t Attributes; + wchar_t PartitionName[36]; +} efi_partition_entry_t; + +/*** POSIX definitions ***/ +#define abs(x) ((x)<0?-(x):(x)) +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + +/* dirent.h */ +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) +#define DT_DIR 4 +#define DT_REG 8 +struct dirent { + unsigned short int d_reclen; + unsigned char d_type; + char_t d_name[FILENAME_MAX]; +}; +typedef struct efi_file_handle_s DIR; +extern DIR *opendir (const char_t *__name); +extern struct dirent *readdir (DIR *__dirp); +extern void rewinddir (DIR *__dirp); +extern int closedir (DIR *__dirp); + +/* errno.h */ +extern int errno; +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +/* stdlib.h */ +#define RAND_MAX 2147483647 +typedef int (*__compar_fn_t) (const void *, const void *); +extern int atoi (const char_t *__nptr); +extern int64_t atol (const char_t *__nptr); +extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base); +extern void *malloc (size_t __size); +extern void *calloc (size_t __nmemb, size_t __size); +extern void *realloc (void *__ptr, size_t __size); +extern void free (void *__ptr); +extern void abort (void); +extern void exit (int __status); +/* exit Boot Services function. Returns 0 on success. */ +extern int exit_bs(void); +extern void *bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); +extern void qsort (void *__base, size_t __nmemb, size_t __size, __compar_fn_t __compar); +extern int mblen (const char *__s, size_t __n); +extern int mbtowc (wchar_t * __pwc, const char * __s, size_t __n); +extern int wctomb (char *__s, wchar_t __wchar); +extern size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n); +extern size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n); +extern void srand(unsigned int __seed); +extern int rand(void); +extern uint8_t *getenv(char_t *name, uintn_t *len); +extern int setenv(char_t *name, uintn_t len, uint8_t *data); + +/* stdio.h */ +#ifndef BUFSIZ +#define BUFSIZ 8192 +#endif +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ +#define stdin (FILE*)ST->ConsoleInHandle +#define stdout (FILE*)ST->ConsoleOutHandle +#define stderr (FILE*)ST->ConsoleErrorHandle +typedef struct efi_file_handle_s FILE; +extern int fclose (FILE *__stream); +extern int fflush (FILE *__stream); +extern int remove (const char_t *__filename); +extern FILE *fopen (const char_t *__filename, const char_t *__modes); +extern size_t fread (void *__ptr, size_t __size, size_t __n, FILE *__stream); +extern size_t fwrite (const void *__ptr, size_t __size, size_t __n, FILE *__s); +extern int fseek (FILE *__stream, long int __off, int __whence); +extern long int ftell (FILE *__stream); +extern int feof (FILE *__stream); +extern int fprintf (FILE *__stream, const char_t *__format, ...); +extern int printf (const char_t *__format, ...); +extern int sprintf (char_t *__s, const char_t *__format, ...); +extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg); +extern int vprintf (const char_t *__format, __builtin_va_list __arg); +extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg); +extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...); +extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg); +extern int getchar (void); +/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */ +extern int getchar_ifany (void); +extern int putchar (int __c); + +/* string.h */ +extern void *memcpy(void *__dest, const void *__src, size_t __n); +extern void *memmove(void *__dest, const void *__src, size_t __n); +extern void *memset(void *__s, int __c, size_t __n); +extern int memcmp(const void *__s1, const void *__s2, size_t __n); +extern void *memchr(const void *__s, int __c, size_t __n); +extern void *memrchr(const void *__s, int __c, size_t __n); +void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl); +void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl); +extern char_t *strcpy (char_t *__dest, const char_t *__src); +extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n); +extern char_t *strcat (char_t *__dest, const char_t *__src); +extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n); +extern int strcmp (const char_t *__s1, const char_t *__s2); +extern int strncmp (const char_t *__s1, const char_t *__s2, size_t __n); +extern char_t *strdup (const char_t *__s); +extern char_t *strchr (const char_t *__s, int __c); +extern char_t *strrchr (const char_t *__s, int __c); +extern char_t *strstr (const char_t *__haystack, const char_t *__needle); +extern char_t *strtok (char_t *__s, const char_t *__delim); +extern char_t *strtok_r (char_t *__s, const char_t *__delim, char_t **__save_ptr); +extern size_t strlen (const char_t *__s); + +/* sys/stat.h */ +#define S_IREAD 0400 /* Read by owner. */ +#define S_IWRITE 0200 /* Write by owner. */ +#define S_IFMT 0170000 /* These bits determine file type. */ +#define S_IFIFO 0010000 /* FIFO. */ +#define S_IFCHR 0020000 /* Character device. */ +#define S_IFDIR 0040000 /* Directory. */ +#define S_IFBLK 0060000 /* Block device. */ +#define S_IFREG 0100000 /* Regular file. */ +#define S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask)) +#define S_ISCHR(mode) S_ISTYPE((mode), S_IFCHR) +#define S_ISDIR(mode) S_ISTYPE((mode), S_IFDIR) +#define S_ISBLK(mode) S_ISTYPE((mode), S_IFBLK) +#define S_ISREG(mode) S_ISTYPE((mode), S_IFREG) +#define S_ISFIFO(mode) S_ISTYPE((mode), S_IFIFO) +struct stat { + mode_t st_mode; + off_t st_size; + blkcnt_t st_blocks; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; +extern int stat (const char_t *__file, struct stat *__buf); +extern int fstat (FILE *__f, struct stat *__buf); +extern int mkdir (const char_t *__path, mode_t __mode); + +/* time.h */ +struct tm { + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] (not set) */ + int tm_yday; /* Days in year.[0-365] (not set) */ + int tm_isdst; /* DST. [-1/0/1]*/ +}; +extern struct tm *localtime (const time_t *__timer); +extern time_t mktime(const struct tm *__tm); +extern time_t time(time_t *__timer); + +/* unistd.h */ +extern unsigned int sleep (unsigned int __seconds); +extern int usleep (unsigned long int __useconds); +extern int unlink (const wchar_t *__filename); +extern int rmdir (const wchar_t *__filename); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEFI_H_ */ diff --git a/libs/posix-uefi/uefi/unistd.c b/libs/posix-uefi/uefi/unistd.c new file mode 100644 index 0000000..0ea6246 --- /dev/null +++ b/libs/posix-uefi/uefi/unistd.c @@ -0,0 +1,55 @@ +/* + * unistd.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 Implementing functions which are defined in unistd.h + * + */ + +#include + +int __remove(const wchar_t *__filename, int isdir); + +int usleep (unsigned long int __useconds) +{ + BS->Stall(__useconds); + return 0; +} + +unsigned int sleep (unsigned int __seconds) +{ + BS->Stall((unsigned long int)__seconds * 1000000UL); + return 0; +} + +int unlink (const wchar_t *__filename) +{ + return __remove(__filename, 0); +} + +int rmdir (const wchar_t *__filename) +{ + return __remove(__filename, 1); +} diff --git a/libs/posix-uefi/utils/OLVASSEL.md b/libs/posix-uefi/utils/OLVASSEL.md new file mode 100644 index 0000000..b19e1db --- /dev/null +++ b/libs/posix-uefi/utils/OLVASSEL.md @@ -0,0 +1,41 @@ +POSIX-UEFI Segédeszközök +======================== + +Ezek kis parancsok, amik besegítenek az UEFI toolchain-edbe (csak libc-t használnak, nincs szükség EFI hedörökre). A POSIX-UEFI +által lefordított .efi kimeneti fájlokat konvertálják olyan különböző formátumú fájlokká, amiket az UEFI firmware használ. + +* __efirom__ - ez PCI Option ROM képet készít +``` +POSIX-UEFI utils - efirom by Michael Brown GPL + +./efirom [--vendor=VVVV] [--device=DDDD] bementifájl kimentifájl +``` + +* __efiffs__ - ez DXE UEFI eszközmeghajtó képet készít (bővebb infó [ebben a wikiben](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware#adding-the-module-to-the-firmware) található arról, hogy hogyan kell a firmwarehez adni). +``` +POSIX-UEFI utils - efiffs by bztsrc@gitlab MIT + +./efiffs [-g ] [-n ] [-v ] [-t ] [-p ] bemenet [kimenet] + + -g a GUID megadása (alapértelmezetten véletlenszám) + -n az eszközmeghajtó neve (pl 'FAT') + -v az eszközmeghajtó verziója (pl '1.0') + -t az ffs típusa (alapértelmezetten 7, EFI_FV_FILETYPE_DRIVER) + -p a pe szekció típusa (alapértelmezetten 16, EFI_SECTION_PE32) + bemenet a bemeneti .efi fájl neve + kimenet a kimeneti fájl neve (alapértelmezetten a bemeneti névből generált) +``` + +* __efidsk__ - indítható lemezképet készít EFI Rendszer Partícióval egy könyvtár tartalmából. A POSIX-EFI-vel lefordított +programodat `EFI/BOOT/BOOTX64.EFI` néven kell bemásolni a könyvtárba, hogy magától elinduljon. +``` +POSIX-UEFI utils - efidsk by bztsrc@gitlab MIT + +./efidsk [-p|-c] [-s ] bekönyvtár kimenet + + -p csak a partíciót mentse, GPT nélkül + -c EFI CDROM mentése (ISO9660 El Torito no emulation boot catalog) + -s a partíció méretének megadása megabájtban (alapértelmezetten 33M) + bekönvtár ennek a könyvtárnak a tartalmából generálja + kimenet kimenti lemezképfájl neve +``` diff --git a/libs/posix-uefi/utils/README.md b/libs/posix-uefi/utils/README.md new file mode 100644 index 0000000..f9e9197 --- /dev/null +++ b/libs/posix-uefi/utils/README.md @@ -0,0 +1,41 @@ +POSIX-UEFI Utilities +==================== + +These are small portable commands to help you with the UEFI toolchain (libc only, no EFI headers needed). They convert the .efi +output that you've compiled with POSIX-UEFI into different file formats required by the UEFI firmware. + +* __efirom__ - creates a PCI Option ROM image +``` +POSIX-UEFI utils - efirom by Michael Brown GPL + +./efirom [--vendor=VVVV] [--device=DDDD] infile outfile +``` + +* __efiffs__ - creates a DXE UEFI driver image (see [this wiki](https://github.com/pbatard/efifs/wiki/Adding-a-driver-to-a-UEFI-firmware#adding-the-module-to-the-firmware) on how to add it to a firmware). +``` +POSIX-UEFI utils - efiffs by bztsrc@gitlab MIT + +./efiffs [-g ] [-n ] [-v ] [-t ] [-p ] infile [outfile] + + -g specify the GUID (defaults to random) + -n specify the driver's name (eg 'FAT') + -v specify the driver's version (eg '1.0') + -t specify the ffs type (defaults to 7, EFI_FV_FILETYPE_DRIVER) + -p specify the pe section type (defaults to 16, EFI_SECTION_PE32) + infile input .efi file + outfile output file name (default generated from infile) +``` + +* __efidsk__ - creates a bootable disk image with EFI System Partition from the contents of a directory. Copy the POSIX-UEFI +compiled file under the given directory as `EFI/BOOT/BOOTX64.EFI` to get it automatically booted. +``` +POSIX-UEFI utils - efidsk by bztsrc@gitlab MIT + +./efidsk [-p|-c] [-s ] indir outfile + + -p save only the partition image without GPT + -c save EFI CDROM (ISO9660 El Torito no emulation boot catalog) + -s set the size of partition in megabytes (defaults to 33M) + indir use the contents of this directory + outfile output image file name +``` diff --git a/libs/posix-uefi/utils/efidsk.c b/libs/posix-uefi/utils/efidsk.c new file mode 100644 index 0000000..9fe8308 --- /dev/null +++ b/libs/posix-uefi/utils/efidsk.c @@ -0,0 +1,648 @@ +/* + * utils/efidsk.c + * + * Copyright (C) 2022 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 small tool to create a disk image with EFI System Partition + * + */ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} __attribute__((packed)) guid_t; +guid_t dguid, pguid; + +/** + * Print usage + */ +void usage(char *cmd) +{ + printf("POSIX-UEFI utils - efidsk by bztsrc@gitlab MIT\r\n\r\n"); + printf("%s [-p|-c] [-s ] indir outfile\r\n\r\n", cmd); + printf(" -p save only the partition image without GPT\r\n"); + printf(" -c save EFI CDROM (ISO9660 El Torito no emulation boot catalog)\r\n"); + printf(" -s set the size of partition in megabytes (defaults to 33M)\r\n"); + printf(" indir use the contents of this directory\r\n"); + printf(" outfile output image file name\r\n"); + exit(1); +} + +#define SECTOR_PER_CLUSTER 1 +#define FIRST_PARTITION 2048 + +struct tm *fat_ts; +int fs_len = 0, skipbytes = 0, fat_nextcluster, fat_bpc, fat_spf, fat_lfncnt, fat_numclu = 67584; +unsigned char *fs_base = NULL; +unsigned char *fat_rootdir, *fat_data, fat_lfn[769]; +uint32_t *fat_fat32_1, *fat_fat32_2; + +/** + * Add a new cluster + */ +unsigned char *fat_newclu(int parent) +{ + int clu; + while(parent != fat_nextcluster && fat_fat32_1[parent] && fat_fat32_1[parent] != 0xFFFFFFF) + parent = fat_fat32_1[parent]; + fat_fat32_1[parent] = fat_fat32_2[parent] = fat_nextcluster; + fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = 0xFFFFFFF; + clu = fat_nextcluster++; + if(fat_nextcluster >= fat_numclu) { fprintf(stderr,"efidsk: not enough space on partition\r\n"); exit(1); } + return fat_data + clu * fat_bpc; +} + +/** + * Read in file name + */ +unsigned char *fat_readlfn(unsigned char *dir, int *clu, int *size, int parent) +{ + uint16_t uc2[256], *u; + unsigned char *s, *d; + int i = 0, n; + memset(fat_lfn, 0, sizeof(fat_lfn)); + if(!dir[0]) return dir; + while(dir[0] == '.') dir += 32; + fat_lfncnt++; + if(parent != 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) { + parent = fat_fat32_1[parent]; + if(!parent || parent == 0xFFFFFFF) return NULL; + dir = fat_data + parent * fat_bpc; + } + if(dir[0xB] != 0xF) { + for(s = dir, d = fat_lfn, i = 0; *s && *s != ' ' && i < 8; i++) + *d++ = *s++; + if(dir[8] && dir[8] != ' ') { + *d++ = '.'; + for(s = dir + 8; *s != ' ' && i < 3; i++) + *d++ = *s++; + } + } else { + memset(uc2, 0, sizeof(uc2)); + n = dir[0] & 0x3F; + u = uc2 + (n - 1) * 13; + while(n--) { + for(i = 0; i < 5; i++) + u[i] = dir[i*2+2] << 8 | dir[i*2+1]; + for(i = 0; i < 6; i++) + u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE]; + u[11] = dir[0x1D] << 8 | dir[0x1C]; + u[12] = dir[0x1F] << 8 | dir[0x1E]; + u -= 13; + dir += 32; + if(!((uint64_t)(dir - fs_base) & (fat_bpc - 1))) { + parent = fat_fat32_1[parent]; + if(!parent || parent == 0xFFFFFFF) return NULL; + dir = fat_data + parent * fat_bpc; + } + } + for(d = fat_lfn, u = uc2; *u; u++) + if(*u < 0x80) { + *d++ = *u; + } else if(*u < 0x800) { + *d++ = ((*u>>6)&0x1F)|0xC0; + *d++ = (*u&0x3F)|0x80; + } else { + *d++ = ((*u>>12)&0x0F)|0xE0; + *d++ = ((*u>>6)&0x3F)|0x80; + *d++ = (*u&0x3F)|0x80; + } + } + *clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A]; + *size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C]; + return dir + 32; +} + +/** + * Write file name + */ +unsigned char *fat_writelfn(unsigned char *dir, char *name, int type, int size, int parent, int clu) +{ + uint16_t uc2[256], *u; + unsigned char *s, c = 0, sfn[12]; + int i, n; + if(name[0] == '.') { + memset(dir, ' ', 11); + memcpy(dir, name, strlen(name)); + } else { + memset(uc2, 0, sizeof(uc2)); + for(n = 0, u = uc2, s = (unsigned char*)name; *s; n++, u++) { + if((*s & 128) != 0) { + if((*s & 32) == 0) { *u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s += 2; } else + if((*s & 16) == 0) { *u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 3; } + else { fprintf(stderr,"efidsk: unable to encode file name '%s'\r\n", name); exit(1); } + } else + *u = *s++; + } + /* don't convert "Microsoft" to "MICROS~1 ", that's patented... */ + sprintf((char*)sfn, "~%07xLFN", fat_lfncnt++); + for(i = 0; i < 11; i++) + c = (((c & 1) << 7) | ((c & 0xfe) >> 1)) + sfn[i]; + n = (n + 12) / 13; + u = uc2 + (n - 1) * 13; + i = 0x40; + while(n--) { + if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) + dir = fat_newclu(parent); + dir[0] = i | (n + 1); + dir[11] = 0xF; + dir[0xD] = c; + memcpy(dir + 1, (unsigned char*)u, 10); + memcpy(dir + 14, (unsigned char*)u + 10, 12); + memcpy(dir + 28, (unsigned char*)u + 22, 4); + i = 0; + u -= 13; + dir += 32; + } + if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) + dir = fat_newclu(parent); + memcpy(dir, sfn, 11); + } + if(type) { + dir[0xB] = 0x10; + } else { + dir[0x1C] = size & 0xFF; dir[0x1D] = (size >> 8) & 0xFF; + dir[0x1E] = (size >> 16) & 0xFF; dir[0x1F] = (size >> 24) & 0xFF; + } + if(!clu) clu = size > 0 || type ? fat_nextcluster : 0; + if(clu < 3) clu = 0; + dir[0x1A] = clu & 0xFF; dir[0x1B] = (clu >> 8) & 0xFF; + dir[0x14] = (clu >> 16) & 0xFF; dir[0x15] = (clu >> 24) & 0xFF; + i = (fat_ts->tm_hour << 11) | (fat_ts->tm_min << 5) | (fat_ts->tm_sec/2); + dir[0xE] = dir[0x16] = i & 0xFF; dir[0xF] = dir[0x17] = (i >> 8) & 0xFF; + i = ((fat_ts->tm_year+1900-1980) << 9) | ((fat_ts->tm_mon+1) << 5) | (fat_ts->tm_mday); + return dir + 32; +} + +/** + * Create a fat file system + */ +void fat_open(int start) +{ + int i; + + if(fat_numclu < 67584) { fprintf(stderr,"efidsk: not enough clusters\r\n"); exit(1); } + /* "format" the partition to FAT32 */ + fs_len = fat_numclu * 512 * SECTOR_PER_CLUSTER; + fs_base = realloc(fs_base, fs_len); + if(!fs_base) { fprintf(stderr,"efidsk: unable to allocate memory\r\n"); exit(1); } + memset(fs_base, 0, fs_len); + memcpy(fs_base + 3, "MSWIN4.1", 8); + fs_base[0xC] = 2; fs_base[0x10] = 2; fs_base[0x15] = 0xF8; fs_base[0x1FE] = 0x55; fs_base[0x1FF] = 0xAA; + fs_base[0x18] = 0x20; fs_base[0x1A] = 0x40; + memcpy(fs_base + 0x1C, &start, 4); + memcpy(fs_base + 0x20, &fat_numclu, 4); + fat_spf = (fat_numclu*4) / 512; + fs_base[0xD] = SECTOR_PER_CLUSTER; fs_base[0xE] = 8; + fs_base[0x24] = fat_spf & 0xFF; fs_base[0x25] = (fat_spf >> 8) & 0xFF; + fs_base[0x26] = (fat_spf >> 16) & 0xFF; fs_base[0x27] = (fat_spf >> 24) & 0xFF; + fs_base[0x2C] = 2; fs_base[0x30] = 1; fs_base[0x32] = 6; fs_base[0x40] = 0x80; fs_base[0x42] = 0x29; + memcpy(fs_base + 0x43, &pguid, 4); + memcpy(fs_base + 0x47, "EFI System FAT32 ", 19); + memcpy(fs_base + 0x200, "RRaA", 4); memcpy(fs_base + 0x3E4, "rrAa", 4); + for(i = 0; i < 8; i++) fs_base[0x3E8 + i] = 0xFF; + fs_base[0x3FE] = 0x55; fs_base[0x3FF] = 0xAA; + fat_bpc = fs_base[0xD] * 512; + fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512; + fat_data = fat_rootdir - 2*fat_bpc; + fat_fat32_1 = (uint32_t*)(&fs_base[fs_base[0xE] * 512]); + fat_fat32_2 = (uint32_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]); + fat_fat32_1[0] = fat_fat32_2[0] = fat_fat32_1[2] = fat_fat32_2[2] = 0x0FFFFFF8; + fat_fat32_1[1] = fat_fat32_2[1] = 0x0FFFFFFF; + fat_nextcluster = 3; +} + +/** + * Add a file to the file system + */ +void fat_add(struct stat *st, char *name, unsigned char *content, int size) +{ + int parent = 2, clu, i, j; + unsigned char *dir = fat_rootdir; + char *end, *fn = strrchr(name, '/'); + if(!fn) fn = name; else fn++; + if(!strcmp(fn, ".") || !strcmp(fn, "..")) return; + if(!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) return; + fat_ts = gmtime(&st->st_mtime); + fn = name; + end = strchr(name, '/'); + if(!end) end = name + strlen(name); + fat_lfncnt = 1; + do { + dir = fat_readlfn(dir, &clu, &j, parent); + if(!dir) return; + if(!memcmp(fat_lfn, fn, end - fn) && !fat_lfn[end - fn]) { + fat_lfncnt = 1; + parent = clu; + dir = fat_data + parent * fat_bpc + 64; + fn = end + 1; + end = *end ? strchr(fn, '/') : NULL; + if(!end) { end = fn + strlen(fn); break; } + } + } while(dir[0]); + dir = fat_writelfn(dir, fn, S_ISDIR(st->st_mode), size, parent, 0); + if(S_ISDIR(st->st_mode)) { + dir = fat_newclu(fat_nextcluster); + dir = fat_writelfn(dir, ".", 1, 0, 2, fat_nextcluster - 1); + dir = fat_writelfn(dir, "..", 1, 0, 2, parent); + } else if(content && size > 0) { + if(fat_nextcluster * fat_bpc + size >= fs_len) { + fprintf(stderr,"efidsk: not enough space on partition\r\n"); + exit(1); + } + memcpy(fat_data + fat_nextcluster * fat_bpc, content, size); + for(i = 0; i < ((size + fat_bpc-1) & ~(fat_bpc-1)); i += fat_bpc, fat_nextcluster++) { + fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = fat_nextcluster+1; + } + fat_fat32_1[fat_nextcluster-1] = fat_fat32_2[fat_nextcluster-1] = 0xFFFFFFF; + } +} + +/** + * Close the file system + */ +void fat_close() +{ + int i; + if(!fs_base || fs_len < 512) return; + fat_nextcluster -= 2; + i = ((fs_len - (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512)/fat_bpc) - fat_nextcluster; + fs_base[0x3E8] = i & 0xFF; fs_base[0x3E9] = (i >> 8) & 0xFF; + fs_base[0x3EA] = (i >> 16) & 0xFF; fs_base[0x3EB] = (i >> 24) & 0xFF; + fs_base[0x3EC] = fat_nextcluster & 0xFF; fs_base[0x3ED] = (fat_nextcluster >> 8) & 0xFF; + fs_base[0x3EE] = (fat_nextcluster >> 16) & 0xFF; fs_base[0x3EF] = (fat_nextcluster >> 24) & 0xFF; + /* copy backup boot sectors */ + memcpy(fs_base + (fs_base[0x32]*512), fs_base, 1024); +} + +/** + * Read a file entirely into memory + */ +long int read_size; +unsigned char* readfileall(char *file) +{ + unsigned char *data=NULL; + FILE *f; + read_size = 0; + if(!file || !*file) return NULL; + f = fopen(file,"r"); + if(f) { + fseek(f, 0L, SEEK_END); + read_size = (long int)ftell(f); + fseek(f, 0L, SEEK_SET); + data = (unsigned char*)malloc(read_size + 1); + if(!data) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); } + memset(data, 0, read_size + 1); + fread(data, read_size, 1, f); + data[read_size] = 0; + fclose(f); + } + return data; +} + +/** + * Recursively parse a directory + */ +void parsedir(char *directory, int parent) +{ + DIR *dir; + struct dirent *ent; + char full[8192]; + unsigned char *tmp; + struct stat st; + + if(!parent && !skipbytes) skipbytes = strlen(directory) + 1; + + if ((dir = opendir(directory)) != NULL) { + while ((ent = readdir(dir)) != NULL) { + if(!parent && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))) continue; + full[0] = 0; + strncat(full, directory, sizeof(full)-1); + strncat(full, "/", sizeof(full)-1); + strncat(full, ent->d_name, sizeof(full)-1); + if(stat(full, &st)) continue; + read_size = 0; + if(S_ISDIR(st.st_mode)) { + fat_add(&st, full + skipbytes, NULL, 0); + if(strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) + parsedir(full, parent+1); + } else + if(S_ISREG(st.st_mode)) { + tmp = readfileall(full); + fat_add(&st, full + skipbytes, tmp, read_size); + if(tmp) free(tmp); + } + } + closedir(dir); + } +} + +/** + * CRC calculation with precalculated lookup table + */ +uint32_t crc32_lookup[256]={ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, + 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, + 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, + 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, + 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, + 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, + 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, + 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, + 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, + 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, + 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, + 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; +uint32_t crc32_calc(unsigned char *start,int length) +{ + uint32_t crc32_val=0xffffffff; + while(length--) crc32_val=(crc32_val>>8)^crc32_lookup[(crc32_val&0xff)^(unsigned char)*start++]; + crc32_val^=0xffffffff; + return crc32_val; +} + +/** + * Write out GUID Partitioning Table + */ +void setint(int val, unsigned char *ptr) { memcpy(ptr,&val,4); } +void writegpt(FILE *f) +{ + guid_t efiguid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA,0x4B,0x00,0xA0,0xC9,0x3E,0xC9,0x3B} }; + int i; + unsigned char *gpt = malloc(FIRST_PARTITION * 512), gpt2[512], *p; + char *name; + if(!gpt) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); } + memset(gpt, 0, FIRST_PARTITION * 512); + + gpt[0x1FE]=0x55; gpt[0x1FF]=0xAA; + memcpy(gpt+0x1B8, &dguid.Data1, 4); /* WinNT disk id */ + /* MBR, EFI System Partition / boot partition. */ + gpt[0x1C0-2]=0x80; /* bootable flag */ + setint(FIRST_PARTITION+1,gpt+0x1C0); /* start CHS */ + gpt[0x1C0+2]=0xC; /* type, LBA FAT32 (0xC) */ + setint(fs_len/512,gpt+0x1C0+4); /* end CHS */ + setint(FIRST_PARTITION,gpt+0x1C0+6); /* start LBA */ + setint(fs_len/512,gpt+0x1C0+10); /* number of sectors */ + /* MBR, protective GPT entry */ + setint(1,gpt+0x1D0); /* start CHS */ + gpt[0x1D0+2]=0xEE; /* type */ + setint(FIRST_PARTITION+1,gpt+0x1D0+4); /* end CHS */ + setint(1,gpt+0x1D0+6); /* start LBA */ + setint(FIRST_PARTITION,gpt+0x1D0+10); /* number of sectors */ + + /* GPT header */ + p = gpt + 512; + memcpy(p,"EFI PART",8); /* magic */ + setint(1,p+10); /* revision */ + setint(92,p+12); /* size */ + setint(1,p+24); /* primary LBA */ + setint(2*FIRST_PARTITION+fat_numclu-2,p+32);/* secondary LBA */ + setint(FIRST_PARTITION,p+40); /* first usable LBA */ + setint(FIRST_PARTITION+fat_numclu,p+48); /* last usable LBA */ + memcpy(p+56,&dguid,sizeof(guid_t)); /* disk UUID */ + setint(2,p+72); /* partitioning table LBA */ + setint((FIRST_PARTITION-2)*512/128,p+80); /* number of entries */ + setint(128,p+84); /* size of one entry */ + p += 512; + + /* GPT, EFI System Partition (ESP) */ + memcpy(p, &efiguid, sizeof(guid_t)); /* entry type */ + memcpy(p+16, &pguid, sizeof(guid_t)); /* partition UUID */ + setint(FIRST_PARTITION,p+32); /* start LBA */ + setint(FIRST_PARTITION+fat_numclu-1,p+40); /* end LBA */ + name = "EFI System Partition"; /* name */ + for(i = 0; name[i]; i++) p[56+i*2] = name[i]; + p += 128; + + /* calculate checksums */ + setint(crc32_calc(gpt+1024,((gpt[512+81]<<8)|gpt[512+80])*128),gpt+512+88); + setint(crc32_calc(gpt+512,92),gpt+512+16); + memcpy(gpt2, gpt+512, 512); + setint(1,gpt2+32); /* secondary lba */ + setint(2*FIRST_PARTITION+fat_numclu-2,gpt2+24); /* primary lba */ + setint(FIRST_PARTITION+fat_numclu,gpt2+72); /* partition lba */ + setint(0,gpt2+16); /* calculate with zero */ + setint(crc32_calc(gpt2,92),gpt2+16); + + fwrite(gpt, 1, FIRST_PARTITION * 512, f); + fwrite(fs_base, 1, fs_len, f); + fwrite(gpt + 1024, 1, (FIRST_PARTITION - 2) * 512, f); + fwrite(gpt2, 1, 512, f); + free(gpt); +} + +/** + * Write out ISO9660 El Torito "no emulation" Boot Catalog + */ +void setinte(int val, unsigned char *ptr) { char *v=(char*)&val; memcpy(ptr,&val,4); ptr[4]=v[3]; ptr[5]=v[2]; ptr[6]=v[1]; ptr[7]=v[0]; } +void writeetbc(FILE *f) +{ + int i; + time_t t; + char isodate[128]; + unsigned char *gpt = malloc(FIRST_PARTITION * 512), *iso; + if(!gpt) { fprintf(stderr, "efidsk: unable to allocate memory\r\n"); exit(1); } + memset(gpt, 0, FIRST_PARTITION * 512); + + t = time(NULL); + fat_ts = gmtime(&t); + sprintf((char*)&isodate, "%04d%02d%02d%02d%02d%02d00", + fat_ts->tm_year+1900,fat_ts->tm_mon+1,fat_ts->tm_mday,fat_ts->tm_hour,fat_ts->tm_min,fat_ts->tm_sec); + iso = gpt + 16*2048; + /* 16th sector: Primary Volume Descriptor */ + iso[0]=1; /* Header ID */ + memcpy(&iso[1], "CD001", 5); + iso[6]=1; /* version */ + for(i=8;i<72;i++) iso[i]=' '; + memcpy(&iso[40], "EFI CDROM", 9); /* Volume Identifier */ + setinte((FIRST_PARTITION*512+fs_len+2047)/2048, &iso[80]); + iso[120]=iso[123]=1; /* Volume Set Size */ + iso[124]=iso[127]=1; /* Volume Sequence Number */ + iso[129]=iso[130]=8; /* logical blocksize (0x800) */ + iso[156]=0x22; /* root directory recordsize */ + setinte(20, &iso[158]); /* root directory LBA */ + setinte(2048, &iso[166]); /* root directory size */ + iso[174]=fat_ts->tm_year; /* root directory create date */ + iso[175]=fat_ts->tm_mon+1; + iso[176]=fat_ts->tm_mday; + iso[177]=fat_ts->tm_hour; + iso[178]=fat_ts->tm_min; + iso[179]=fat_ts->tm_sec; + iso[180]=0; /* timezone UTC (GMT) */ + iso[181]=2; /* root directory flags (0=hidden,1=directory) */ + iso[184]=1; /* root directory number */ + iso[188]=1; /* root directory filename length */ + for(i=190;i<813;i++) iso[i]=' '; /* Volume data */ + memcpy(&iso[318], "POSIX-UEFI ", 49); + memcpy(&iso[446], "EFIDSK", 6); + memcpy(&iso[574], "POSIX-UEFI", 11); + for(i=702;i<813;i++) iso[i]=' '; /* file descriptors */ + memcpy(&iso[813], &isodate, 16); /* volume create date */ + memcpy(&iso[830], &isodate, 16); /* volume modify date */ + for(i=847;i<863;i++) iso[i]='0'; /* volume expiration date */ + for(i=864;i<880;i++) iso[i]='0'; /* volume shown date */ + iso[881]=1; /* filestructure version */ + for(i=883;i<1395;i++) iso[i]=' '; /* file descriptors */ + /* 17th sector: Boot Record Descriptor */ + iso[2048]=0; /* Header ID */ + memcpy(&iso[2049], "CD001", 5); + iso[2054]=1; /* version */ + memcpy(&iso[2055], "EL TORITO SPECIFICATION", 23); + setinte(19, &iso[2048+71]); /* Boot Catalog LBA */ + /* 18th sector: Volume Descritor Terminator */ + iso[4096]=0xFF; /* Header ID */ + memcpy(&iso[4097], "CD001", 5); + iso[4102]=1; /* version */ + /* 19th sector: Boot Catalog */ + /* --- UEFI, Validation Entry + Initial/Default Entry + Final --- */ + iso[6144]=0x91; /* Header ID, Validation Entry, Final */ + iso[6145]=0xEF; /* Platform EFI */ + iso[6176]=0x88; /* Bootable, Initial/Default Entry */ + iso[6182]=1; /* Sector Count */ + setint(FIRST_PARTITION/4, &iso[6184]); /* ESP Start LBA */ + /* 20th sector: Root Directory */ + /* . */ + iso[8192]=0x21 + 1; /* recordsize */ + setinte(20, &iso[8194]); /* LBA */ + setinte(2048, &iso[8202]); /* size */ + iso[8210]=fat_ts->tm_year; /* date */ + iso[8211]=fat_ts->tm_mon+1; + iso[8212]=fat_ts->tm_mday; + iso[8213]=fat_ts->tm_hour; + iso[8214]=fat_ts->tm_min; + iso[8215]=fat_ts->tm_sec; + iso[8216]=0; /* timezone UTC (GMT) */ + iso[8217]=2; /* flags (0=hidden,1=directory) */ + iso[8220]=1; /* serial */ + iso[8224]=1; /* filename length */ + iso[8225]=0; /* filename '.' */ + /* .. */ + iso[8226]=0x21 + 1; /* recordsize */ + setinte(20, &iso[8228]); /* LBA */ + setinte(2048, &iso[8236]); /* size */ + iso[8244]=fat_ts->tm_year; /* date */ + iso[8245]=fat_ts->tm_mon+1; + iso[8246]=fat_ts->tm_mday; + iso[8247]=fat_ts->tm_hour; + iso[8248]=fat_ts->tm_min; + iso[8249]=fat_ts->tm_sec; + iso[8250]=0; /* timezone UTC (GMT) */ + iso[8251]=2; /* flags (0=hidden,1=directory) */ + iso[8254]=1; /* serial */ + iso[8258]=1; /* filename length */ + iso[8259]='\001'; /* filename '..' */ + + fwrite(gpt, 1, FIRST_PARTITION * 512, f); + fwrite(fs_base, 1, fs_len, f); + free(gpt); +} + +/** + * Main function + */ +int main(int argc, char **argv) +{ + FILE *f; + int i, part = 0, cdrom = 0; + char *in = NULL, *out = NULL; + + /* get random GUIDs */ + srand(time(NULL)); + i = rand(); memcpy(&((uint8_t*)&dguid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&dguid)[12], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&pguid)[12], &i, 4); + + /* parse command line */ + for(i = 1; i < argc && argv[i]; i++) + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'p': part++; break; + case 'c': cdrom++; break; + case 's': fat_numclu = atoi(argv[++i]) * 2048; break; + default: usage(argv[0]); break; + } + } else + if(!in) in = argv[i]; else + if(!out) out = argv[i]; else + usage(argv[0]); + if(!out) usage(argv[0]); + + /* generate file system image */ + remove(out); + fat_open(part ? 0 : FIRST_PARTITION); + parsedir(in, 0); + fat_close(); + + /* write out image */ + if(fs_base) { + f = fopen(out, "wb"); + if(!f) { + fprintf(stderr, "efidsk: unable to write '%s'\r\n", out); + return 2; + } + if(!part) { + if(!cdrom) + writegpt(f); + else + writeetbc(f); + } else + fwrite(fs_base, 1, fs_len, f); + fclose(f); + free(fs_base); + } + + return 0; +} diff --git a/libs/posix-uefi/utils/efiffs.c b/libs/posix-uefi/utils/efiffs.c new file mode 100644 index 0000000..5fcb8ab --- /dev/null +++ b/libs/posix-uefi/utils/efiffs.c @@ -0,0 +1,269 @@ +/* + * utils/efiffs.c + * + * Copyright (C) 2022 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 small tool to convert an .efi file to an .ffs file + * + */ + +#include +#include +#include +#include +#include + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} __attribute__((packed)) guid_t; + +/** + * Print usage + */ +void usage(char *cmd) +{ + printf("POSIX-UEFI utils - efiffs by bztsrc@gitlab MIT\r\n\r\n"); + printf("%s [-g ] [-n ] [-v ] [-t ] [-p ] infile [outfile]\r\n\r\n", cmd); + printf(" -g specify the GUID (defaults to random)\r\n"); + printf(" -n specify the driver's name (eg 'FAT')\r\n"); + printf(" -v specify the driver's version (eg '1.0')\r\n"); + printf(" -t specify the ffs type (defaults to 7, EFI_FV_FILETYPE_DRIVER)\r\n"); + printf(" -p specify the pe section type (defaults to 16, EFI_SECTION_PE32)\r\n"); + printf(" infile input .efi file\r\n"); + printf(" outfile output file name (default generated from infile)\r\n"); + exit(1); +} + +/** + * Convert hex string into integer + */ +unsigned int gethex(char *ptr, int len) +{ + unsigned int ret = 0; + for(;len--;ptr++) { + if(*ptr>='0' && *ptr<='9') { ret <<= 4; ret += (unsigned int)(*ptr-'0'); } + else if(*ptr >= 'a' && *ptr <= 'f') { ret <<= 4; ret += (unsigned int)(*ptr-'a'+10); } + else if(*ptr >= 'A' && *ptr <= 'F') { ret <<= 4; ret += (unsigned int)(*ptr-'A'+10); } + else break; + } + return ret; +} + +/** + * Parse a GUID in string into binary representation + */ +void getguid(char *ptr, guid_t *guid) +{ + int i; + + if(!ptr || !*ptr || ptr[8] != '-' || ptr[13] != '-' || ptr[18] != '-') { + fprintf(stderr, "efiffs: bad GUID format\r\n"); + return; + } + guid->Data1 = gethex(ptr, 8); ptr += 9; + guid->Data2 = gethex(ptr, 4); ptr += 5; + guid->Data3 = gethex(ptr, 4); ptr += 5; + guid->Data4[0] = gethex(ptr, 2); ptr += 2; + guid->Data4[1] = gethex(ptr, 2); ptr += 2; if(*ptr == '-') ptr++; + for(i = 2; i < 8; i++, ptr += 2) guid->Data4[i] = gethex(ptr, 2); +} + +/** + * Parse ffs type + */ +int gettype(char *str) +{ + static const char *types[] = { + NULL, "RAW", "FREEFORM", "SECURITY_CORE", "PEI_CORE", "DXE_CORE", "PEIM", "DRIVER", "COMBINED_PEIM_DRIVER", + "APPLICATION", "SMM", "FIRMWARE_VOLUME_IMAGE", "COMBINED_SMM_DXE", "SMM_CORE", NULL }; + int i; + + i = atoi(str); + if(i > 0 && i < (int)(sizeof(types)/sizeof(types[0]))) return i; + + if(!memcmp(str, "EFI_FV_FILETYPE_", 16)) str += 16; + for(i = 1; types[i] && strcmp(str, types[i]); i++); + if(!types[i]) { + fprintf(stderr, "efiffs: invalid ffs type, available values:\r\n"); + for(i = 1; types[i]; i++) + fprintf(stderr, " EFI_FV_FILETYPE_%s\r\n", types[i]); + return 7; /* EFI_FV_FILETYPE_DRIVER */ + } + return i; +} + +/** + * Parse section type + */ +int getsec(char *str) +{ + static const char *types[] = { + "PE32", "PIC", "TE", "DXE_DEPEX", "VERSION", "USER_INTERFACE", "COMPATIBILITY16", + "FIRMWARE_VOLUME_IMAGE", "FREEFORM_SUBTYPE_GUID", "RAW", "RESERVED", "PEI_DEPEX", "SMM_DEPEX", NULL }; + int i; + + i = atoi(str); + if(i == 1 || i == 2 || i >= 16) return i; + + if(!memcmp(str, "EFI_SECTION_", 12)) str += 12; + if(!strcmp(str, "COMPRESSION")) return 1; + if(!strcmp(str, "GUID_DEFINED")) return 2; + for(i = 0; types[i] && strcmp(str, types[i]); i++); + if(!types[i]) { + fprintf(stderr, "efiffs: invalid section type, available values:\r\n"); + fprintf(stderr, " EFI_SECTION_COMPRESSION\r\n EFI_SECTION_GUID_DEFINED\r\n"); + for(i = 0; types[i]; i++) + fprintf(stderr, " EFI_SECTION_%s\r\n", types[i]); + return 16; /* EFI_SECTION_PE32 */ + } + return i + 16; +} + +/** + * Calculate checksum + */ +uint8_t checksum8(uint8_t *buff, int len) +{ + uint8_t ret = 0; + int i; + + for(i = 0; i < len; i++) + ret = (uint8_t)(ret + buff[i]); + return (uint8_t)(0x100 - ret); +} + +/** + * Main function + */ +int main(int argc, char **argv) +{ + FILE *f; + int i, size, len; + int filetype = 7; /* EFI_FV_FILETYPE_DRIVER */ + int sectype = 16; /* EFI_SECTION_PE32 */ + char *in = NULL, *out = NULL, *name = NULL, *ver = NULL; + uint8_t *buff = NULL, *sec = NULL; + guid_t guid; + + /* get a random GUID */ + srand(time(NULL)); + i = rand(); memcpy(&((uint8_t*)&guid)[0], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[4], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[8], &i, 4); + i = rand(); memcpy(&((uint8_t*)&guid)[12], &i, 4); + + /* parse command line */ + for(i = 1; i < argc && argv[i]; i++) + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'g': getguid(argv[++i], &guid); break; + case 'n': name = argv[++i]; break; + case 'v': ver = argv[++i]; break; + case 't': filetype = gettype(argv[++i]); break; + case 'p': sectype = getsec(argv[++i]); break; + default: usage(argv[0]); break; + } + } else + if(!in) in = argv[i]; else + if(!out) out = argv[i]; else + usage(argv[0]); + if(!in) usage(argv[0]); + + /* get input data */ + f = fopen(in, "rb"); + if(!f) { + fprintf(stderr, "efiffs: unable to read '%s'\r\n", in); + return 2; + } + fseek(f, 0L, SEEK_END); + size = (int)ftell(f); + fseek(f, 0L, SEEK_SET); + len = 24 + 12 + 4 + size + (name ? 6 + 2 * strlen(name) : 0) + (ver ? 6 + 2 * strlen(ver) : 0); + buff = (uint8_t*)malloc(len); + if(!buff) { fprintf(stderr, "efiffs: unable to allocate memory\r\n"); return 2; } + memset(buff, 0, len); + sec = buff + 24; + /* add the PE section */ + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = sectype; + fread(sec + 4, 1, size, f); + fclose(f); + sec += 4 + ((size + 3) & ~3); + /* add the name section */ + if(name) { + size = 6 + 2 * strlen(name); + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = 0x15; /* EFI_SECTION_USER_INTERFACE */ + for(i = 0; name[i]; i++) + sec[4 + 2 * i] = name[i]; + sec += ((size + 3) & ~3); + } + /* add the version section */ + if(ver) { + size = 6 + 2 * strlen(ver); + sec[0] = size & 0xff; + sec[1] = (size >> 8) & 0xff; + sec[2] = (size >> 16) & 0xff; + sec[3] = 0x14; /* EFI_SECTION_VERSION */ + for(i = 0; ver[i]; i++) + sec[4 + 2 * i] = ver[i]; + sec += ((size + 3) & ~3); + } + + /* calculate ffs header fields */ + len = (int)((uintptr_t)sec - (uintptr_t)buff); + memcpy(buff, &guid, 16); + buff[0x12] = filetype; + buff[0x14] = len & 0xff; + buff[0x15] = (len >> 8) & 0xff; + buff[0x16] = (len >> 16) & 0xff; + buff[0x11] = 0xAA; + buff[0x10] = checksum8(buff, 24); + + /* write out image */ + if(!out) { + i = strlen(in); + out = (char*)malloc(i + 5); + if(!out) { fprintf(stderr, "efiffs: unable to allocate memory\r\n"); return 2; } + strcpy(out, in); + strcpy(!strcmp(out + i - 4, ".efi") ? out + i - 4 : out + i, ".ffs"); + } + f = fopen(out, "wb"); + if(!f) { + fprintf(stderr, "efiffs: unable to write '%s'\r\n", out); + return 2; + } + fwrite(buff, 1, len, f); + fclose(f); + + free(buff); + return 0; +} diff --git a/libs/posix-uefi/utils/efirom.c b/libs/posix-uefi/utils/efirom.c new file mode 100644 index 0000000..cef1e5f --- /dev/null +++ b/libs/posix-uefi/utils/efirom.c @@ -0,0 +1,1258 @@ +/* + * utils/efirom.c + * + * Copyright (C) 2009 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * modifications for gnuefi by bzt (bztsrc@gitlab) + * + * This file is part of the POSIX-UEFI package. + * @brief small tool to convert an .efi file to a .rom file + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "POSIX-UEFI utils - efirom by Michael Brown GPL\r\n\r\n" ); + eprintf ( "%s [--vendor=VVVV] [--device=DDDD] " + "infile outfile\n", program_name ); +} + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) +typedef uint64_t UINTN; +typedef UINTN EFI_TPL; + +typedef struct _EFI_DEVICE_PATH_PROTOCOL { + uint8_t Type; + uint8_t SubType; + uint8_t Length[2]; +} EFI_DEVICE_PATH_PROTOCOL; + +typedef struct _EFI_DEVICE_PATH_PROTOCOL _EFI_DEVICE_PATH; +typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH; + +#ifndef _EFI_LINK_H +#define _EFI_LINK_H + +/*++ + +Copyright (c) 1998 Intel Corporation + +Module Name: + + link.h (renamed efilink.h to avoid conflicts) + +Abstract: + + EFI link list macro's + + + +Revision History + +--*/ + +#ifndef EFI_NT_EMUL + +// +// List entry - doubly linked list +// + +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY; + +#endif + + +// +// VOID +// InitializeListHead( +// LIST_ENTRY *ListHead +// ); +// + +#define InitializeListHead(ListHead) \ + (ListHead)->Flink = ListHead; \ + (ListHead)->Blink = ListHead; + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define _RemoveEntryList(Entry) { \ + LIST_ENTRY *_Blink, *_Flink; \ + _Flink = (Entry)->Flink; \ + _Blink = (Entry)->Blink; \ + _Blink->Flink = _Flink; \ + _Flink->Blink = _Blink; \ + } + +#if EFI_DEBUG + #define RemoveEntryList(Entry) \ + _RemoveEntryList(Entry); \ + (Entry)->Flink = (LIST_ENTRY *) BAD_POINTER; \ + (Entry)->Blink = (LIST_ENTRY *) BAD_POINTER; +#else + #define RemoveEntryList(Entry) \ + _RemoveEntryList(Entry); +#endif + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + LIST_ENTRY *_ListHead, *_Blink; \ + _ListHead = (ListHead); \ + _Blink = _ListHead->Blink; \ + (Entry)->Flink = _ListHead; \ + (Entry)->Blink = _Blink; \ + _Blink->Flink = (Entry); \ + _ListHead->Blink = (Entry); \ + } + +// +// VOID +// InsertHeadList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertHeadList(ListHead,Entry) {\ + LIST_ENTRY *_ListHead, *_Flink; \ + _ListHead = (ListHead); \ + _Flink = _ListHead->Flink; \ + (Entry)->Flink = _Flink; \ + (Entry)->Blink = _ListHead; \ + _Flink->Blink = (Entry); \ + _ListHead->Flink = (Entry); \ + } + +// VOID +// SwapListEntries( +// PLIST_ENTRY Entry1, +// PLIST_ENTRY Entry2 +// ); +// +// Put Entry2 before Entry1 +// +#define SwapListEntries(Entry1,Entry2) {\ + LIST_ENTRY *Entry1Flink, *Entry1Blink; \ + LIST_ENTRY *Entry2Flink, *Entry2Blink; \ + Entry2Flink = (Entry2)->Flink; \ + Entry2Blink = (Entry2)->Blink; \ + Entry1Flink = (Entry1)->Flink; \ + Entry1Blink = (Entry1)->Blink; \ + Entry2Blink->Flink = Entry2Flink; \ + Entry2Flink->Blink = Entry2Blink; \ + (Entry2)->Flink = Entry1; \ + (Entry2)->Blink = Entry1Blink; \ + Entry1Blink->Flink = (Entry2); \ + (Entry1)->Blink = (Entry2); \ + } + +// +// EFI_FIELD_OFFSET - returns the byte offset to a field within a structure +// + +#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field))) + +// +// CONTAINING_RECORD - returns a pointer to the structure +// from one of it's elements. +// + +#define _CR(Record, TYPE, Field) \ + ((TYPE *) ( (CHAR8 *)(Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + +#if EFI_DEBUG + #define CR(Record, TYPE, Field, Sig) \ + _CR(Record, TYPE, Field)->Signature != Sig ? \ + (TYPE *) ASSERT_STRUCT(_CR(Record, TYPE, Field), Record) : \ + _CR(Record, TYPE, Field) +#else + #define CR(Record, TYPE, Field, Signature) \ + _CR(Record, TYPE, Field) +#endif + + +// +// A lock structure +// + +typedef struct _FLOCK { + EFI_TPL Tpl; + EFI_TPL OwnerTpl; + UINTN Lock; +} FLOCK; + +#endif + +/* + PE32+ header file + */ +#ifndef _PE_H +#define _PE_H + +#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ +#define IMAGE_OS2_SIGNATURE 0x454E // NE +#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE +#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 +#define IMAGE_EDOS_SIGNATURE 0x44454550 // PEED + + +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + uint16_t e_magic; // Magic number + uint16_t e_cblp; // Bytes on last page of file + uint16_t e_cp; // Pages in file + uint16_t e_crlc; // Relocations + uint16_t e_cparhdr; // Size of header in paragraphs + uint16_t e_minalloc; // Minimum extra paragraphs needed + uint16_t e_maxalloc; // Maximum extra paragraphs needed + uint16_t e_ss; // Initial (relative) SS value + uint16_t e_sp; // Initial SP value + uint16_t e_csum; // Checksum + uint16_t e_ip; // Initial IP value + uint16_t e_cs; // Initial (relative) CS value + uint16_t e_lfarlc; // File address of relocation table + uint16_t e_ovno; // Overlay number + uint16_t e_res[4]; // Reserved words + uint16_t e_oemid; // OEM identifier (for e_oeminfo) + uint16_t e_oeminfo; // OEM information; e_oemid specific + uint16_t e_res2[10]; // Reserved words + uint32_t e_lfanew; // File address of new exe header + } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header + uint16_t ne_magic; // Magic number + uint8_t ne_ver; // Version number + uint8_t ne_rev; // Revision number + uint16_t ne_enttab; // Offset of Entry Table + uint16_t ne_cbenttab; // Number of bytes in Entry Table + uint32_t ne_crc; // Checksum of whole file + uint16_t ne_flags; // Flag uint16_t + uint16_t ne_autodata; // Automatic data segment number + uint16_t ne_heap; // Initial heap allocation + uint16_t ne_stack; // Initial stack allocation + uint32_t ne_csip; // Initial CS:IP setting + uint32_t ne_sssp; // Initial SS:SP setting + uint16_t ne_cseg; // Count of file segments + uint16_t ne_cmod; // Entries in Module Reference Table + uint16_t ne_cbnrestab; // Size of non-resident name table + uint16_t ne_segtab; // Offset of Segment Table + uint16_t ne_rsrctab; // Offset of Resource Table + uint16_t ne_restab; // Offset of resident name table + uint16_t ne_modtab; // Offset of Module Reference Table + uint16_t ne_imptab; // Offset of Imported Names Table + uint32_t ne_nrestab; // Offset of Non-resident Names Table + uint16_t ne_cmovent; // Count of movable entries + uint16_t ne_align; // Segment alignment shift count + uint16_t ne_cres; // Count of resource segments + uint8_t ne_exetyp; // Target Operating system + uint8_t ne_flagsothers; // Other .EXE flags + uint16_t ne_pretthunks; // offset to return thunks + uint16_t ne_psegrefbytes; // offset to segment ref. bytes + uint16_t ne_swaparea; // Minimum code swap area size + uint16_t ne_expver; // Expected Windows version number + } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; + +// +// File header format. +// + +typedef struct _IMAGE_FILE_HEADER { + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. + +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I386 0x14c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x162 // MIPS little-endian, 0540 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x1c2 // Arm/Thumb +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_IA64 0x200 // IA-64 +#define IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine +#define IMAGE_FILE_MACHINE_EBC 0xebc // EFI Byte Code +#define IMAGE_FILE_MACHINE_X64 0x8664 // x86_64 +// +// Directory format. +// + +typedef struct _IMAGE_DATA_DIRECTORY { + uint32_t VirtualAddress; + uint32_t Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +// +// Optional header format. +// + +typedef struct _IMAGE_OPTIONAL_HEADER { + // + // Standard fields. + // + + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + + // + // NT additional fields. + // + + uint32_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Reserved1; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint32_t SizeOfStackReserve; + uint32_t SizeOfStackCommit; + uint32_t SizeOfHeapReserve; + uint32_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_ROM_OPTIONAL_HEADER { + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + uint32_t BaseOfBss; + uint32_t GprMask; + uint32_t CprMask[4]; + uint32_t GpValue; +} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER; + +#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 +#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 +#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224 + +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS { + uint32_t Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + +typedef struct _IMAGE_ROM_HEADERS { + IMAGE_FILE_HEADER FileHeader; + IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; +} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS; + +#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ + ((uint32_t)ntheader + \ + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ + )) + + +// Subsystem Values + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image run in the Posix character subsystem. + + +// Directory Entries + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // Description String +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory + +// +// Section header format. +// + +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. + +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// +// Symbol format. +// + + +#define IMAGE_SIZEOF_SYMBOL 18 + +// +// Section values. +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// + +#define IMAGE_SYM_UNDEFINED (uint16_t)0 // Symbol is undefined or is common. +#define IMAGE_SYM_ABSOLUTE (uint16_t)-1 // Symbol is an absolute value. +#define IMAGE_SYM_DEBUG (uint16_t)-2 // Symbol is a special debug item. + +// +// Type (fundamental) values. +// + +#define IMAGE_SYM_TYPE_NULL 0 // no type. +#define IMAGE_SYM_TYPE_VOID 1 // +#define IMAGE_SYM_TYPE_CHAR 2 // type character. +#define IMAGE_SYM_TYPE_SHORT 3 // type short integer. +#define IMAGE_SYM_TYPE_INT 4 // +#define IMAGE_SYM_TYPE_LONG 5 // +#define IMAGE_SYM_TYPE_FLOAT 6 // +#define IMAGE_SYM_TYPE_DOUBLE 7 // +#define IMAGE_SYM_TYPE_STRUCT 8 // +#define IMAGE_SYM_TYPE_UNION 9 // +#define IMAGE_SYM_TYPE_ENUM 10 // enumeration. +#define IMAGE_SYM_TYPE_MOE 11 // member of enumeration. +#define IMAGE_SYM_TYPE_BYTE 12 // +#define IMAGE_SYM_TYPE_WORD 13 // +#define IMAGE_SYM_TYPE_UINT 14 // +#define IMAGE_SYM_TYPE_DWORD 15 // + +// +// Type (derived) values. +// + +#define IMAGE_SYM_DTYPE_NULL 0 // no derived type. +#define IMAGE_SYM_DTYPE_POINTER 1 // pointer. +#define IMAGE_SYM_DTYPE_FUNCTION 2 // function. +#define IMAGE_SYM_DTYPE_ARRAY 3 // array. + +// +// Storage classes. +// + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +// new +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// type packing constants + +#define N_BTMASK 017 +#define N_TMASK 060 +#define N_TMASK1 0300 +#define N_TMASK2 0360 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +// MACROS + +// +// Communal selection types. +// + +#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define IMAGE_COMDAT_SELECT_ANY 2 +#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + + +// +// Relocation format. +// + +typedef struct _IMAGE_RELOCATION { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + uint16_t Type; +} IMAGE_RELOCATION; + +#define IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// + +#define IMAGE_REL_I386_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 01 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 02 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 06 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB 07 // Direct 32-bit reference to the symbols virtual address, base not included +#define IMAGE_REL_I386_SEG12 011 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address +#define IMAGE_REL_I386_SECTION 012 +#define IMAGE_REL_I386_SECREL 013 +#define IMAGE_REL_I386_REL32 024 // PC-relative 32-bit reference to the symbols virtual address + +// +// MIPS relocation types. +// + +#define IMAGE_REL_MIPS_ABSOLUTE 0 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_MIPS_REFHALF 01 +#define IMAGE_REL_MIPS_REFWORD 02 +#define IMAGE_REL_MIPS_JMPADDR 03 +#define IMAGE_REL_MIPS_REFHI 04 +#define IMAGE_REL_MIPS_REFLO 05 +#define IMAGE_REL_MIPS_GPREL 06 +#define IMAGE_REL_MIPS_LITERAL 07 +#define IMAGE_REL_MIPS_SECTION 012 +#define IMAGE_REL_MIPS_SECREL 013 +#define IMAGE_REL_MIPS_REFWORDNB 042 +#define IMAGE_REL_MIPS_PAIR 045 + +// +// Alpha Relocation types. +// + +#define IMAGE_REL_ALPHA_ABSOLUTE 0x0 +#define IMAGE_REL_ALPHA_REFLONG 0x1 +#define IMAGE_REL_ALPHA_REFQUAD 0x2 +#define IMAGE_REL_ALPHA_GPREL32 0x3 +#define IMAGE_REL_ALPHA_LITERAL 0x4 +#define IMAGE_REL_ALPHA_LITUSE 0x5 +#define IMAGE_REL_ALPHA_GPDISP 0x6 +#define IMAGE_REL_ALPHA_BRADDR 0x7 +#define IMAGE_REL_ALPHA_HINT 0x8 +#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x9 +#define IMAGE_REL_ALPHA_REFHI 0xA +#define IMAGE_REL_ALPHA_REFLO 0xB +#define IMAGE_REL_ALPHA_PAIR 0xC +#define IMAGE_REL_ALPHA_MATCH 0xD +#define IMAGE_REL_ALPHA_SECTION 0xE +#define IMAGE_REL_ALPHA_SECREL 0xF +#define IMAGE_REL_ALPHA_REFLONGNB 0x10 + +// +// IBM PowerPC relocation types. +// + +#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP +#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address +#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address +#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute) +#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address +#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword) +#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative) +#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative) +#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base +#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword) + +#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base +#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr) +#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number +#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code +#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction + +#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type + +// Flag bits in IMAGE_RELOCATION.TYPE + +#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it +#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken +#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken +#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc) + +// +// Based relocation format. +// + +typedef struct _IMAGE_BASE_RELOCATION { + uint32_t VirtualAddress; + uint32_t SizeOfBlock; +// uint16_t TypeOffset[1]; +} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; + +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +// +// Based relocation types. +// + +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 + +// +// Line number format. +// + +typedef struct _IMAGE_LINENUMBER { + union { + uint32_t SymbolTableIndex; // Symbol table index of function name if Linenumber is 0. + uint32_t VirtualAddress; // Virtual address of line number. + } Type; + uint16_t Linenumber; // Line number. +} IMAGE_LINENUMBER; + +#define IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// + +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + uint8_t Name[16]; // File member name - `/' terminated. + uint8_t Date[12]; // File member date - decimal. + uint8_t UserID[6]; // File member user id - decimal. + uint8_t GroupID[6]; // File member group id - decimal. + uint8_t Mode[8]; // File member mode - octal. + uint8_t Size[10]; // File member size - decimal. + uint8_t EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// +// DLL support. +// + +// +// Export Format +// + +typedef struct _IMAGE_EXPORT_DIRECTORY { + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t Name; + uint32_t Base; + uint32_t NumberOfFunctions; + uint32_t NumberOfNames; + uint32_t *AddressOfFunctions; + uint32_t *AddressOfNames; + uint32_t *AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// +// Import Format +// + +typedef struct _IMAGE_IMPORT_BY_NAME { + uint16_t Hint; + uint8_t Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA { + union { + uint32_t Function; + uint32_t Ordinal; + PIMAGE_IMPORT_BY_NAME AddressOfData; + } u1; +} IMAGE_THUNK_DATA, *PIMAGE_THUNK_DATA; + +#define IMAGE_ORDINAL_FLAG 0x80000000 +#define IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0) +#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + uint32_t Characteristics; + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t Name; + PIMAGE_THUNK_DATA FirstThunk; +} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; + +#endif + +#ifndef _PCI22_H +#define _PCI22_H + +/*++ + +Copyright (c) 1999 Intel Corporation + +Module Name: + + pci22.h + +Abstract: + Support for PCI 2.2 standard. + + + + +Revision History + +--*/ + +#ifdef SOFT_SDV +#define PCI_MAX_BUS 1 +#else +#define PCI_MAX_BUS 255 +#endif + +#define PCI_MAX_DEVICE 31 +#define PCI_MAX_FUNC 7 + +// +// Command +// +#define PCI_VGA_PALETTE_SNOOP_DISABLED 0x20 + +#pragma pack(1) +typedef struct { + uint16_t VendorId; + uint16_t DeviceId; + uint16_t Command; + uint16_t Status; + uint8_t RevisionID; + uint8_t ClassCode[3]; + uint8_t CacheLineSize; + uint8_t LaytencyTimer; + uint8_t HeaderType; + uint8_t BIST; +} PCI_DEVICE_INDEPENDENT_REGION; + +typedef struct { + uint32_t Bar[6]; + uint32_t CISPtr; + uint16_t SubsystemVendorID; + uint16_t SubsystemID; + uint32_t ExpansionRomBar; + uint32_t Reserved[2]; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint8_t MinGnt; + uint8_t MaxLat; +} PCI_DEVICE_HEADER_TYPE_REGION; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_DEVICE_HEADER_TYPE_REGION Device; +} PCI_TYPE00; + +typedef struct { + uint32_t Bar[2]; + uint8_t PrimaryBus; + uint8_t SecondaryBus; + uint8_t SubordinateBus; + uint8_t SecondaryLatencyTimer; + uint8_t IoBase; + uint8_t IoLimit; + uint16_t SecondaryStatus; + uint16_t MemoryBase; + uint16_t MemoryLimit; + uint16_t PrefetchableMemoryBase; + uint16_t PrefetchableMemoryLimit; + uint32_t PrefetchableBaseUpper32; + uint32_t PrefetchableLimitUpper32; + uint16_t IoBaseUpper16; + uint16_t IoLimitUpper16; + uint32_t Reserved; + uint32_t ExpansionRomBAR; + uint8_t InterruptLine; + uint8_t InterruptPin; + uint16_t BridgeControl; +} PCI_BRIDGE_CONTROL_REGISTER; + +#define PCI_CLASS_DISPLAY_CTRL 0x03 +#define PCI_CLASS_VGA 0x00 + +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_ISA 0x01 +#define PCI_CLASS_ISA_POSITIVE_DECODE 0x80 + +#define PCI_CLASS_NETWORK 0x02 +#define PCI_CLASS_ETHERNET 0x00 + +#define HEADER_TYPE_DEVICE 0x00 +#define HEADER_TYPE_PCI_TO_PCI_BRIDGE 0x01 +#define HEADER_TYPE_MULTI_FUNCTION 0x80 +#define HEADER_LAYOUT_CODE 0x7f + +#define IS_PCI_BRIDGE(_p) ((((_p)->Hdr.HeaderType) & HEADER_LAYOUT_CODE) == HEADER_TYPE_PCI_TO_PCI_BRIDGE) +#define IS_PCI_MULTI_FUNC(_p) (((_p)->Hdr.HeaderType) & HEADER_TYPE_MULTI_FUNCTION) + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_BRIDGE_CONTROL_REGISTER Bridge; +} PCI_TYPE01; + +typedef struct { + uint8_t Register; + uint8_t Function; + uint8_t Device; + uint8_t Bus; + uint8_t Reserved[4]; +} DEFIO_PCI_ADDR; + +typedef struct { + uint32_t Reg : 8; + uint32_t Func : 3; + uint32_t Dev : 5; + uint32_t Bus : 8; + uint32_t Reserved: 7; + uint32_t Enable : 1; +} PCI_CONFIG_ACCESS_CF8; + +#pragma pack() + +#define EFI_ROOT_BRIDGE_LIST 'eprb' +typedef struct { + UINTN Signature; + + uint16_t BridgeNumber; + uint16_t PrimaryBus; + uint16_t SubordinateBus; + + EFI_DEVICE_PATH *DevicePath; + + LIST_ENTRY Link; +} PCI_ROOT_BRIDGE_ENTRY; + + +#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55 +#define EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE 0x0EF1 +#define PCI_DATA_STRUCTURE_SIGNATURE EFI_SIGNATURE_32('P','C','I','R') + +#pragma pack(1) +typedef struct { + uint16_t Signature; // 0xaa55 + uint8_t Reserved[0x16]; + uint16_t PcirOffset; +} PCI_EXPANSION_ROM_HEADER; + + +typedef struct { + uint16_t Signature; // 0xaa55 + uint16_t InitializationSize; + uint16_t EfiSignature; // 0x0EF1 + uint16_t EfiSubsystem; + uint16_t EfiMachineType; + uint8_t Reserved[0x0A]; + uint16_t EfiImageHeaderOffset; + uint16_t PcirOffset; +} EFI_PCI_EXPANSION_ROM_HEADER; + +typedef struct { + uint32_t Signature; // "PCIR" + uint16_t VendorId; + uint16_t DeviceId; + uint16_t Reserved0; + uint16_t Length; + uint8_t Revision; + uint8_t ClassCode[3]; + uint16_t ImageLength; + uint16_t CodeRevision; + uint8_t CodeType; + uint8_t Indicator; + uint16_t Reserved1; +} PCI_DATA_STRUCTURE; +#pragma pack() + +#endif + + +/** Command-line options */ +struct options { + uint16_t vendor; + uint16_t device; +}; + +/** + * Allocate memory + * + * @v len Length of memory to allocate + * @ret ptr Pointer to allocated memory + */ +static void * xmalloc ( size_t len ) { + void *ptr; + + ptr = malloc ( len ); + if ( ! ptr ) { + eprintf ( "Could not allocate %zd bytes\n", len ); + exit ( 1 ); + } + + return ptr; +} + +/** + * Get file size + * + * @v file File + * @v len File size + */ +/* +static size_t file_size ( FILE *file ) { + ssize_t len; + + return len; +} +*/ +/** + * Read information from PE headers + * + * @v pe PE file + * @ret machine Machine type + * @ret subsystem EFI subsystem + */ +static void read_pe_info ( void *pe, uint16_t *machine, + uint16_t *subsystem ) { + IMAGE_DOS_HEADER *dos; + union { + IMAGE_NT_HEADERS nt64; + } *nt; + + /* Locate NT header */ + dos = pe; + nt = ( pe + dos->e_lfanew ); + + /* issue 4: TianoCore demands subsystem 10, so we must use EFI_APPLICATION + * in the PE header. Therefore we force EFI_ROM subsystem in this code here. */ + if(nt->nt64.OptionalHeader.Subsystem == 10) + nt->nt64.OptionalHeader.Subsystem = 13; + + /* Parse out PE information */ + *machine = nt->nt64.FileHeader.Machine; + *subsystem = nt->nt64.OptionalHeader.Subsystem; +} + +/** + * Convert EFI image to ROM image + * + * @v pe EFI file + * @v rom ROM file + */ +static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) { + struct { + EFI_PCI_EXPANSION_ROM_HEADER rom; + PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) )); + uint8_t checksum; + } *headers; + struct stat pe_stat; + size_t pe_size; + size_t rom_size; + void *buf; + void *payload; + unsigned int i; + uint8_t checksum; + + /* Determine PE file size */ + if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) { + eprintf ( "Could not stat PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + pe_size = pe_stat.st_size; + + /* Determine ROM file size */ + rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 ); + + /* Allocate ROM buffer and read in PE file */ + buf = xmalloc ( rom_size ); + memset ( buf, 0, rom_size ); + headers = buf; + payload = ( buf + sizeof ( *headers ) ); + if ( fread ( payload, pe_size, 1, pe ) != 1 ) { + eprintf ( "Could not read PE file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } + + /* Construct ROM header */ + headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE; + headers->rom.InitializationSize = ( rom_size / 512 ); + headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE; + read_pe_info ( payload, &headers->rom.EfiMachineType, + &headers->rom.EfiSubsystem ); + headers->rom.EfiImageHeaderOffset = sizeof ( *headers ); + headers->rom.PcirOffset = + offsetof ( typeof ( *headers ), pci ); + headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE; + headers->pci.VendorId = opts->vendor ? opts->vendor : 0x8086; + headers->pci.DeviceId = opts->device ? opts->device : 0x100E; + headers->pci.Length = sizeof ( headers->pci ); + headers->pci.ClassCode[0] = PCI_CLASS_NETWORK; + headers->pci.ImageLength = ( rom_size / 512 ); + headers->pci.CodeType = 0x03; /* No constant in EFI headers? */ + headers->pci.Indicator = 0x80; /* No constant in EFI headers? */ + + /* Fix image checksum */ + for ( i = 0, checksum = 0 ; i < rom_size ; i++ ) + checksum += *( ( uint8_t * ) buf + i ); + headers->checksum -= checksum; + + /* Write out ROM */ + if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) { + eprintf ( "Could not write ROM file: %s\n", + strerror ( errno ) ); + exit ( 1 ); + } +} + +/** + * Parse command-line options + * + * @v argc Argument count + * @v argv Argument list + * @v opts Options structure to populate + */ +static int parse_options ( const int argc, char **argv, + struct options *opts ) { + char *end; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "vendor", required_argument, NULL, 'v' }, + { "device", required_argument, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "v:d:h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 'v': + opts->vendor = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid vendor \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'd': + opts->device = strtoul ( optarg, &end, 16 ); + if ( *end ) { + eprintf ( "Invalid device \"%s\"\n", optarg ); + exit ( 2 ); + } + break; + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + +int main ( int argc, char **argv ) { + struct options opts = { + }; + unsigned int infile_index; + const char *infile_name; + const char *outfile_name; + FILE *infile; + FILE *outfile; + + /* Parse command-line arguments */ + infile_index = parse_options ( argc, argv, &opts ); + if ( argc != ( infile_index + 2 ) ) { + print_help ( argv[0] ); + exit ( 2 ); + } + infile_name = argv[infile_index]; + outfile_name = argv[infile_index + 1]; + + /* Open input and output files */ + infile = fopen ( infile_name, "r" ); + if ( ! infile ) { + eprintf ( "Could not open %s for reading: %s\n", + infile_name, strerror ( errno ) ); + exit ( 1 ); + } + outfile = fopen ( outfile_name, "w" ); + if ( ! outfile ) { + eprintf ( "Could not open %s for writing: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + + /* Convert file */ + make_efi_rom ( infile, outfile, &opts ); + + fclose ( outfile ); + fclose ( infile ); + + return 0; +}