diff --git a/.gitignore b/.gitignore index 9003691..c384f87 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -# cp437 tool -cp437/cp437 -cp437/cp437.exe -cp437.tmp -*_cp437 +# GNU C +*.a +*.o # Watcom C *.err @@ -11,3 +9,13 @@ cp437.tmp # Python __pycache__ *.pyc + + +# cp437 tool +cp437/cp437 +cp437/cp437.exe +*_cp437 + +# UEFI +NvVars +pci?????.bin diff --git a/acpi/ACPI.EXE b/acpi/ACPI.EXE new file mode 100644 index 0000000..f7afbce Binary files /dev/null and b/acpi/ACPI.EXE differ diff --git a/acpi/Makefile b/acpi/Makefile new file mode 100644 index 0000000..8364e87 --- /dev/null +++ b/acpi/Makefile @@ -0,0 +1,22 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Makefile for compiling C-based tools with Watcom. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +SYSTEM = DOS +OBJS = acpi.obj clib.obj +DEST = ACPI.EXE + +!include ../clib/watcom.mk diff --git a/acpi/README.md b/acpi/README.md new file mode 100644 index 0000000..be05404 --- /dev/null +++ b/acpi/README.md @@ -0,0 +1,12 @@ +acpi +==== +DOS tool for probing ACPI behavior in some chipsets. + +Usage +----- +Run `ACPI` on a system with Intel PIIX4 or VIA ACPI. Follow any on-screen prompts. + +Building +-------- +* **Windows:** Run `wmake` from an OpenWatcom "Build Environment" command prompt. +* **Linux:** Run `wmake` with OpenWatcom tools present in `$PATH`. diff --git a/acpi/acpi.c b/acpi/acpi.c new file mode 100644 index 0000000..8169b18 --- /dev/null +++ b/acpi/acpi.c @@ -0,0 +1,139 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box Probing Tools distribution. + * + * ACPI probing tool. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + * + * ┌──────────────────────────────────────────────────────────────┐ + * │ This file is UTF-8 encoded. If this text is surrounded by │ + * │ garbage, please tell your editor to open this file as UTF-8. │ + * └──────────────────────────────────────────────────────────────┘ + */ +#include +#include +#include "clib.h" + + +char dummy_buf[256]; + + +void +probe_intel(uint8_t dev, uint8_t func) +{ + uint16_t acpi_base; + int type; + + acpi_base = pci_readw(0, dev, func, 0x40); + printf("ACPI base register = %04X\n", acpi_base); + acpi_base &= 0xff80; + + printf("PMCNTRL 04=%04X 40=%04X\n", inw(acpi_base | 0x04), inw(acpi_base | 0x40)); + + printf("Enter hex sleep type to try: "); + scanf("%x%*c", &type); + + printf("Press ENTER to try sleep %02X through 40...", type); + gets(dummy_buf); + outw(acpi_base | 0x40, 0x2000 | (type << 10)); + + printf("Nothing?\nPress ENTER to try sleep %02X through 04...", type); + gets(dummy_buf); + outw(acpi_base | 0x04, 0x2000 | (type << 10)); + printf("Nothing still?\n"); +} + + +void +probe_via(uint8_t dev, uint8_t func, uint8_t is586) +{ + uint16_t acpi_base; + int type; + + acpi_base = pci_readw(0, dev, func, is586 ? 0x20 : 0x48); + printf("ACPI base register = %04X\n", acpi_base); + acpi_base &= 0xff00; + + printf("PMCNTRL 04=%04X F0=%04X\n", inw(acpi_base | 0x04), inw(acpi_base | 0xf0)); + + printf("Enter hex sleep type to try: "); + scanf("%x%*c", &type); + + printf("Press ENTER to try sleep %02X through F0...", type); + gets(dummy_buf); + outw(acpi_base | 0xf0, 0x2000 | (type << 10)); + + printf("Nothing?\nPress ENTER to try sleep %02X through 04...", type); + gets(dummy_buf); + outw(acpi_base | 0x04, 0x2000 | (type << 10)); + printf("Nothing still?\n"); +} + + +int +main(int argc, char **argv) +{ + uint8_t dev, func; + uint16_t ven_id, dev_id; + uint32_t cf8; + +#ifdef __WATCOMC__ + /* Disable stdout buffering. */ + setbuf(stdout, NULL); +#endif + +#ifndef DEBUG + /* Test for PCI presence. */ + outl(0xcf8, 0x80000000); + cf8 = inl(0xcf8); + if (cf8 == 0xffffffff) { + printf("Port CF8h is not responding. Does this system even have PCI?\n"); + return 1; + } +#endif + + for (dev = 0; dev < 32; dev++) { + if (!(pci_readb(0, dev, 0, 0x0e) & 0x80)) + continue; + + ven_id = pci_readw(0, dev, 3, 0); + dev_id = pci_readw(0, dev, 3, 2); + if ((ven_id == 0x8086) && (dev_id == 0x7113)) { + printf("Found PIIX4 ACPI at device %02X function %d\n", dev, 3); + probe_intel(dev, 3); + return 0; + } else if ((ven_id == 0x1055) && (dev_id == 0x9463)) { + printf("Found SLC90E66 ACPI at device %02X function %d\n", dev, 3); + probe_intel(dev, 3); + return 0; + } else if ((ven_id == 0x1106) && (dev_id == 0x3040)) { + printf("Found VT82C586 ACPI at device %02X function %d\n", dev, 3); + probe_via(dev, 3, 1); + return 0; + } else if ((ven_id == 0x1106) && (dev_id == 0x3050)) { + printf("Found VT82C596 ACPI at device %02X function %d\n", dev, 3); + probe_via(dev, 3, 0); + return 0; + } else { + ven_id = pci_readw(0, dev, 4, 0); + dev_id = pci_readw(0, dev, 4, 2); + if ((ven_id == 0x1106) && (dev_id == 0x3057)) { + printf("Found VT82C686 ACPI at device %02X function %d\n", dev, 4); + probe_via(dev, 4, 0); + return 0; + } + } + } + + printf("No interesting ACPI device found\n"); + return 1; +} diff --git a/clib/README.md b/clib/README.md new file mode 100644 index 0000000..e77b5e7 --- /dev/null +++ b/clib/README.md @@ -0,0 +1,3 @@ +clib +==== +Not a probing tool. Common library for C-based tools. diff --git a/clib/clib.c b/clib/clib.c new file mode 100644 index 0000000..8bcacb3 --- /dev/null +++ b/clib/clib.c @@ -0,0 +1,405 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box Probing Tools distribution. + * + * Common library for C-based tools. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + * + */ +#ifdef __POSIX_UEFI__ +# include +#else +# include +# include +# include +# include +# ifdef __WATCOMC__ +# include +# include +# endif +#endif +#include "clib.h" + + +#ifdef __WATCOMC__ +static union REGPACK rp; /* things break if this is not a global variable... */ +#endif + + +/* String functions. */ +int +parse_hex_u8(char *val, uint8_t *dest) +{ + uint32_t dest32; + int ret = parse_hex_u32(val, &dest32); + *dest = dest32; + return ret; +} + + +int +parse_hex_u16(char *val, uint16_t *dest) +{ + uint32_t dest32; + int ret = parse_hex_u32(val, &dest32); + *dest = dest32; + return ret; +} + + +int +parse_hex_u32(char *val, uint32_t *dest) +{ + int i, len = strlen(val); + uint8_t digit; + + *dest = 0; + for (i = 0; i < len; i++) { + if ((val[i] >= 0x30) && (val[i] <= 0x39)) + digit = val[i] - 0x30; + else if ((val[i] >= 0x41) && (val[i] <= 0x46)) + digit = val[i] - 0x37; + else if ((val[i] >= 0x61) && (val[i] <= 0x66)) + digit = val[i] - 0x57; + else + return 0; + *dest = (*dest << 4) | digit; + } + + return 1; +} + + +/* Comparator functions. */ +int +comp_ui8(const void *elem1, const void *elem2) +{ + uint8_t a = *((uint8_t *) elem1); + uint8_t b = *((uint8_t *) elem2); + return ((a < b) ? -1 : ((a > b) ? 1 : 0)); +} + + +/* System functions. */ +#ifdef __WATCOMC__ +/* Defined in header. */ +#elif defined(__GNUC__) +void +cli() +{ + __asm__("cli"); +} + + +void +sti() +{ + __asm__("sti"); +} +#else +void +cli() +{ +} + + +void +sti() +{ +} +#endif + + +/* Terminal functions. */ +#ifdef __WATCOMC__ +int +term_get_size_x() +{ + struct videoconfig vc; + _getvideoconfig(&vc); + return vc.numtextcols; +} + + +int +term_get_size_y() +{ + struct videoconfig vc; + _getvideoconfig(&vc); + return vc.numtextrows; +} + + +int +term_get_cursor_pos(uint8_t *x, uint8_t *y) +{ + rp.h.ah = 0x03; + rp.h.bh = 0x00; + intr(0x10, &rp); + *x = rp.h.dl; + *y = rp.h.dh; + return 1; +} + + +int +term_set_cursor_pos(uint8_t x, uint8_t y) +{ + rp.h.ah = 0x02; + rp.h.dl = x; + rp.h.dh = y; + intr(0x10, &rp); + return 1; +} + + +void +term_finallinebreak() +{ + /* DOS already outputs a final line break. */ +} +#else +int +term_get_size_x() +{ + return 80; +} + + +int +term_get_size_y() +{ + return 25; +} + + +int +term_get_cursor_pos(uint8_t *x, uint8_t *y) +{ + return 0; +} + + +int +term_set_cursor_pos(uint8_t x, uint8_t y) +{ + return 0; +} + + +void +term_finallinebreak() +{ + printf("\n"); +} +#endif + + +/* Port I/O functions. */ +#ifdef __WATCOMC__ +/* Defined in header. */ +#elif defined(__GNUC__) +uint8_t +inb(uint16_t port) +{ + uint8_t ret; + __asm__ __volatile__("inb %1, %0" : "=a" (ret) : "Nd" (port)); + return ret; +} + + +void +outb(uint16_t port, uint8_t val) +{ + __asm__ __volatile__("outb %0, %1" : : "a" (val), "Nd" (port)); +} + + +uint16_t +inw(uint16_t port) +{ + uint16_t ret; + __asm__ __volatile__("inw %1, %0" : "=a" (ret) : "Nd" (port)); + return ret; +} + + +void +outw(uint16_t port, uint16_t val) +{ + __asm__ __volatile__("outw %0, %1" : : "a" (val), "Nd" (port)); +} + + +uint32_t +inl(uint16_t port) +{ + uint32_t ret; + __asm__ __volatile__("inl %1, %0" : "=a" (ret) : "Nd" (port)); + return ret; +} + + +void +outl(uint16_t port, uint32_t val) +{ + __asm__ __volatile__("outl %0, %1" : : "a" (val), "Nd" (port)); +} +#else +uint8_t +inb(uint16_t port) +{ + return 0xff; +} + + +void +outb(uint16_t port, uint8_t val) +{ +} + + +uint16_t +inw(uint16_t port) +{ + return 0xffff; +} + + +void +outw(uint16_t port, uint16_t val) +{ +} + + +uint32_t +inl(uint16_t port) +{ + return 0xffffffff; +} + + +void +outl(uint16_t port, uint32_t val) +{ +} +#endif + + +/* PCI I/O functions. */ +uint32_t +pci_cf8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) +{ + /* Generate a PCI port CF8h dword. */ + multi_t ret; + ret.u8[3] = 0x80; + ret.u8[2] = bus; + ret.u8[1] = dev << 3; + ret.u8[1] |= func & 7; + ret.u8[0] = reg & 0xfc; + return ret.u32; +} + + +uint8_t +pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) +{ + uint8_t ret; + uint16_t data_port = 0xcfc | (reg & 0x03); + uint32_t cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + ret = inb(data_port); + sti(); + return ret; +} + + +uint16_t +pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) +{ + uint16_t ret, data_port = 0xcfc | (reg & 0x02); + uint32_t cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + ret = inw(data_port); + sti(); + return ret; +} + + +uint32_t +pci_readl(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) +{ + uint32_t ret, cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + ret = inl(0xcfc); + sti(); + return ret; +} + + +void +pci_writeb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t val) +{ + uint16_t data_port = 0xcfc | (reg & 0x03); + uint32_t cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + outb(data_port, val); + sti(); +} + + +void +pci_writew(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t val) +{ + uint16_t data_port = 0xcfc | (reg & 0x02); + uint32_t cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + outw(data_port, val); + sti(); +} + + +void +pci_writel(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val) +{ + uint32_t cf8 = pci_cf8(bus, dev, func, reg); + cli(); + outl(0xcf8, cf8); + outl(0xcfc, val); + sti(); +} + + +/* File I/O functions. */ +void +fseek_to(FILE *f, long offset) +{ + fseek(f, offset, SEEK_SET); + +#ifdef __POSIX_UEFI__ + /* Work around broken fseek implementation. */ + long pos = ftell(f); + if (pos == offset) + return; + + uint8_t dummy[512]; + while (pos < offset) { + fread(&dummy, MIN(sizeof(dummy), offset - pos), 1, f); + pos = ftell(f); + } +#endif +} diff --git a/clib/clib.h b/clib/clib.h new file mode 100644 index 0000000..2d39a7f --- /dev/null +++ b/clib/clib.h @@ -0,0 +1,125 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box Probing Tools distribution. + * + * Definitions for the common library for C-based tools. + * + * + * + * Authors: RichardG, + * + * Copyright 2021 RichardG. + * + */ +#ifndef WLIB_H +# define WLIB_H + +/* Common macros. */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +/* Compiler compatibility macros. */ +#ifdef __GNUC__ +# define PACKED __attribute__((packed)) +#else +# define PACKED +#endif + + +#pragma pack(push, 0) +/* Convenience type for breaking a dword value down into words and bytes. */ +typedef union { + uint8_t u8[4]; + uint16_t u16[2]; + uint32_t u32; +} multi_t; +#pragma pack(pop) + + +/* String functions. */ +extern int parse_hex_u8(char *val, uint8_t *dest); +extern int parse_hex_u16(char *val, uint16_t *dest); +extern int parse_hex_u32(char *val, uint32_t *dest); + +/* Comparator functions. */ +extern int comp_ui8(const void *elem1, const void *elem2); + +/* System functions. */ +#ifdef __WATCOMC__ +void cli(); +# pragma aux cli = "cli"; +void sti(); +# pragma aux sti = "sti"; +#else +extern void cli(); +extern void sti(); +#endif + +/* Terminal functions. */ +extern int term_get_size_x(); +extern int term_get_size_y(); +extern int term_get_cursor_pos(uint8_t *x, uint8_t *y); +extern int term_set_cursor_pos(uint8_t x, uint8_t y); +extern void term_finallinebreak(); + +/* Port I/O functions. */ +#ifdef __WATCOMC__ +uint8_t inb(uint16_t port); +# pragma aux inb = "in al, dx" parm [dx] value [al]; +void outb(uint16_t port, uint8_t data); +# pragma aux outb = "out dx, al" parm [dx] [al]; +uint16_t inw(uint16_t port); +# pragma aux inw = "in ax, dx" parm [dx] value [ax]; +void outw(uint16_t port, uint16_t data); +# pragma aux outw = "out dx, ax" parm [dx] [ax]; +# ifdef M_I386 +uint32_t inl(uint16_t port); +# pragma aux inl = "in eax, dx" parm [dx] value [eax]; +void outl(uint16_t port, uint32_t data); +# pragma aux outl = "out dx, eax" parm [dx] [eax]; +# else +/* Some manual prefixing trickery to perform 32-bit I/O and access + the extended part of EAX in real mode. Exchanging is necessary + due to Watcom ignoring the order registers are specified in... */ +uint32_t inl(uint16_t port); +# pragma aux inl = "db 0x66" "in ax, dx" /* in eax, dx */ \ + "mov cx, ax" \ + "db 0x66, 0xc1, 0xe8, 0x10" /* shr eax, 16 */ \ + "xchg ax, cx" \ + parm [dx] \ + value [ax cx]; +void outl(uint16_t port, uint32_t data); +# pragma aux outl = "xchg ax, cx" \ + "db 0x66, 0xc1, 0xe0, 0x10" /* shl eax, 16 */ \ + "mov ax, cx" \ + "db 0x66" "out dx, ax" /* out dx, eax */ \ + parm [dx] [ax cx] \ + modify [ax cx]; +# endif +#else +extern uint8_t inb(uint16_t port); +extern void outb(uint16_t port, uint8_t data); +extern uint16_t inw(uint16_t port); +extern void outw(uint16_t port, uint16_t data); +extern uint32_t inl(uint16_t port); +extern void outl(uint16_t port, uint32_t data); +#endif + +/* PCI I/O functions. */ +extern uint32_t pci_cf8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); +extern uint8_t pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); +extern uint16_t pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); +extern uint32_t pci_readl(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); +extern void pci_writeb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t val); +extern void pci_writew(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t val); +extern void pci_writel(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val); + +/* File I/O functions. */ +extern void fseek_to(FILE *f, long offset); + +#endif diff --git a/clib/uefi.mk b/clib/uefi.mk new file mode 100644 index 0000000..1ccb012 --- /dev/null +++ b/clib/uefi.mk @@ -0,0 +1,25 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Base makefile for compiling C-based tools with POSIX-UEFI. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +VPATH = . ../clib + +export TARGET = $(DEST) +export SRCS = $(OBJS:.o=.c) +export CFLAGS = -mno-sse -D__POSIX_UEFI__ -I../clib +export USE_GCC = 1 + +include uefi/Makefile diff --git a/clib/watcom.mk b/clib/watcom.mk new file mode 100644 index 0000000..03774ed --- /dev/null +++ b/clib/watcom.mk @@ -0,0 +1,88 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Base makefile for compiling C-based tools with Watcom. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +# Establish host-specific stuff. +!ifdef __UNIX__ +DEL = rm -f +CP437 = cp437 +SLASH = / +!else +DEL = del +CP437 = cp437.exe +SLASH = \ +!if "$(SYSTEM)" == "HOST" +# Build a Windows NT character-mode executable on Windows, +# as that is not the default target (Win16 is). +SYSTEM = NT +DEST = $(DEST).exe +!endif +!endif + +# Establish target information. +!if "$(SYSTEM)" == "DOS" +CC = wcc +CP437_CONV = y +!else +CC = wcc386 +CP437_CONV = n +!endif +LINK = wlink + +# Establish target C flags. +CFLAGS = -i=..$(SLASH)clib $(CFLAGS) +!if "$(SYSTEM)" != "HOST" +CFLAGS = -bt=$(SYSTEM) $(CFLAGS) +!endif + + +# Include clib. +.c: ../clib + +# Compile source file into object file. +.c.obj +!if "$(CP437_CONV)" == "y" + @..$(SLASH)cp437$(SLASH)$(CP437) $< + $(CC) -bt=$(SYSTEM) $(CFLAGS) $<_cp437 + @$(DEL) $<_cp437 +!else + $(CC) $(CFLAGS) $< +!endif + +# Default target, which must be the first! +all: ..$(SLASH)cp437$(SLASH)$(CP437) $(DEST) + +# cp437 host tool compilation target. +# Only valid if cp437 conversion is needed. +..$(SLASH)cp437$(SLASH)$(CP437): +!if "$(CP437_CONV)" == "y" + cd ..$(SLASH)cp437 & wmake $(CP437) +!endif + +# Main target. +$(DEST): $(OBJS) + %write $@.lnk NAME $@ +!if "$(SYSTEM)" != "HOST" + %write $@.lnk SYSTEM $(SYSTEM) +!endif + %write $@.lnk FILE {$(OBJS)} + $(LINK) $(LDFLAGS) @$@.lnk + $(DEL) $@.lnk + +clean: .symbolic + $(DEL) $(OBJS) + $(DEL) $(DEST) + $(DEL) *.err diff --git a/cp437/Makefile b/cp437/Makefile new file mode 100644 index 0000000..af51541 --- /dev/null +++ b/cp437/Makefile @@ -0,0 +1,22 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Makefile for compiling C-based tools with Watcom. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +SYSTEM = HOST +OBJS = cp437.obj +DEST = cp437 + +!include ../clib/watcom.mk diff --git a/cp437/README.md b/cp437/README.md index f60da94..b2534f8 100644 --- a/cp437/README.md +++ b/cp437/README.md @@ -14,5 +14,5 @@ Building -------- This tool is automatically built as needed by the build scripts for other tools. Alternatively: -* **Windows:** Run `build.bat` from an OpenWatcom "Build Environment" command prompt. -* **Linux:** Run `./build.sh` with OpenWatcom tools present in `$PATH`. +* **Windows:** Run `wmake` from an OpenWatcom "Build Environment" command prompt. +* **Linux:** Run `wmake` with OpenWatcom tools present in `$PATH`. diff --git a/cp437/build.bat b/cp437/build.bat deleted file mode 100644 index 1f25ab4..0000000 --- a/cp437/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -..\lib\build_watcom_host.bat cp437.c diff --git a/cp437/build.sh b/cp437/build.sh deleted file mode 100644 index 58850a2..0000000 --- a/cp437/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec ../lib/build_watcom_host.sh cp437.c diff --git a/cp437/cp437.c b/cp437/cp437.c index 31e7823..c1cf91b 100644 --- a/cp437/cp437.c +++ b/cp437/cp437.c @@ -56,7 +56,7 @@ main(int argc, char **argv) if (argc < 2) { printf("Usage:\n"); printf("\n"); - printf("cp437 infile [infile...]\n"); + printf("%s infile [infile...]\n", argv[0]); printf("- Converts UTF-8 input file(s) to CP437 output file(s) with .cp437 appended.\n"); printf(" The new file names are also printed to stdout.\n"); return 1; diff --git a/lib/build_watcom_dos.bat b/lib/build_watcom_dos.bat deleted file mode 100644 index 0b6e5dd..0000000 --- a/lib/build_watcom_dos.bat +++ /dev/null @@ -1,61 +0,0 @@ -@echo off -:: -:: 86Box A hypervisor and IBM PC system emulator that specializes in -:: running old operating systems and software designed for IBM -:: PC systems and compatibles from 1981 through fairly recent -:: system designs based on the PCI bus. -:: -:: This file is part of the 86Box Probing Tools distribution. -:: -:: Universal Windows build script for Watcom C-based DOS tools. -:: -:: -:: -:: Authors: RichardG, -:: -:: Copyright 2021 RichardG. -:: - -:: Check for Watcom environment. -if "x%WATCOM%" == "x" ( - echo *** WATCOM environment variable not set. Make sure you're on an OpenWatcom - echo "Build Environment" command prompt. - exit /b 1 -) - -:: Check for cp437 tool and build it if necessary. -if not exist ..\cp437\cp437.exe ( - echo *** Building cp437 conversion tool for your host system... - pushd ..\cp437 - call build.bat - popd - if errorlevel 1 exit /b %errorlevel% -) - -:: Convert source file to CP437. -echo *** Converting source to CP437... -..\cp437\cp437.exe %* > cp437.tmp -if errorlevel 1 ( - echo *** Conversion failed. - exit /b 2 -) - -:: Generate output file name. -set srcfile=%1 -set destfile=%srcfile:~0,-2%.exe -setlocal enabledelayedexpansion -for %%i in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do set "destfile=!destfile:%%i=%%i!" - -:: Call compiler. -echo *** Building... -set srcfiles= -for /f "delims=" %%i in (cp437.tmp) do set srcfiles=!srcfiles! %%i -wcl -bcl=dos -i=..\lib -fe="!destfile!" %srcfiles% - -:: Check for success. -if errorlevel 1 ( - echo *** Build failed. - exit /b 3 -) else ( - echo *** Build successful. -) diff --git a/lib/build_watcom_dos.sh b/lib/build_watcom_dos.sh deleted file mode 100644 index b2391d4..0000000 --- a/lib/build_watcom_dos.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh -# -# 86Box A hypervisor and IBM PC system emulator that specializes in -# running old operating systems and software designed for IBM -# PC systems and compatibles from 1981 through fairly recent -# system designs based on the PCI bus. -# -# This file is part of the 86Box Probing Tools distribution. -# -# Universal *nix build script for Watcom C-based DOS tools. -# -# -# -# Authors: RichardG, -# -# Copyright 2021 RichardG. -# - -# Check for Watcom environment. -if ! wcl -v >/dev/null 2>&1 -then - echo '***' Watcom compiler not found. Make sure OpenWatcom is installed and in \$PATH. - exit 1 -fi - -# Check for cp437 tool and build it if necessary. -if [ ! -x ../cp437/cp437 ] -then - echo '***' Building cp437 conversion tool for your host system... - pushd ../cp437 - if ! ./build.sh - then - exit $? - fi - popd -fi - -# Convert source files to CP437. -echo '***' Converting source to CP437... -if ! ../cp437/cp437 "$@" > cp437.tmp -then - echo '***' Conversion failed. - exit 2 -fi - -# Generate output file name. -destfile=$(basename "$1" .c | tr [:lower:] [:upper:]).EXE - -# Call compiler and check for success. -if wcl -bcl=dos -fo="$destfile" $(cat cp437.tmp) -then - echo '***' Build successful. -else - echo '***' Build failed. - exit 3 -fi diff --git a/lib/build_watcom_host.bat b/lib/build_watcom_host.bat deleted file mode 100644 index 05f67c7..0000000 --- a/lib/build_watcom_host.bat +++ /dev/null @@ -1,40 +0,0 @@ -@echo off -:: -:: 86Box A hypervisor and IBM PC system emulator that specializes in -:: running old operating systems and software designed for IBM -:: PC systems and compatibles from 1981 through fairly recent -:: system designs based on the PCI bus. -:: -:: This file is part of the 86Box Probing Tools distribution. -:: -:: Universal Windows build script for Watcom C-based host tools. -:: -:: -:: -:: Authors: RichardG, -:: -:: Copyright 2021 RichardG. -:: - -:: Check for Watcom environment. -if "x%WATCOM%" == "x" ( - echo *** WATCOM environment variable not set. Make sure you're on an OpenWatcom - echo "Build Environment" command prompt. - exit /b 1 -) - -:: Generate output file name. -set srcfile=%1 -set destfile=%srcfile:~0,-2%.exe - -:: Call compiler. -echo *** Building... -wcl386 -bcl=nt -fo="%destfile%" %* - -:: Check for success. -if errorlevel 1 ( - echo *** Build failed. - exit /b 4 -) else ( - echo *** Build successful. -) diff --git a/lib/build_watcom_host.sh b/lib/build_watcom_host.sh deleted file mode 100644 index f47a586..0000000 --- a/lib/build_watcom_host.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# -# 86Box A hypervisor and IBM PC system emulator that specializes in -# running old operating systems and software designed for IBM -# PC systems and compatibles from 1981 through fairly recent -# system designs based on the PCI bus. -# -# This file is part of the 86Box Probing Tools distribution. -# -# Universal *nix build script for Watcom C-based host tools. -# -# -# -# Authors: RichardG, -# -# Copyright 2021 RichardG. -# - -if ! wcl386 -v >/dev/null 2>&1 -then - echo '***' Watcom compiler not found. Make sure OpenWatcom is installed and in \$PATH. - exit 1 -fi - -# Generate output file name. -destfile=$(basename "$1" .c) - -# Call compiler and check for success. -if wcl386 -bcl=linux -fo="$destfile" "$@" -then - echo '***' Build successful. - chmod +x "$destfile" -else - echo '***' Build failed. - exit 4 -fi diff --git a/lib/wlib.c b/lib/wlib.c deleted file mode 100644 index a890586..0000000 --- a/lib/wlib.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box Probing Tools distribution. - * - * Common functions for Watcom C-based tools. - * - * - * - * Authors: RichardG, - * - * Copyright 2021 RichardG. - * - */ -#include -#include "wlib.h" - - -int -comp_ui8(const void *elem1, const void *elem2) -{ - uint8_t a = *((uint8_t *) elem1); - uint8_t b = *((uint8_t *) elem2); - return ((a < b) ? -1 : ((a > b) ? 1 : 0)); -} - - -uint32_t -pci_cf8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) -{ - /* Generate a PCI port CF8h dword. */ - multi_t ret; - ret.u8[3] = 0x80; - ret.u8[2] = bus; - ret.u8[1] = dev << 3; - ret.u8[1] |= func & 7; - ret.u8[0] = reg & 0xfc; - return ret.u32; -} - - -uint8_t -pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) -{ - uint8_t ret; - uint16_t data_port = 0xcfc | (reg & 0x03); - uint32_t cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - ret = inb(data_port); - sti(); - return ret; -} - - -uint16_t -pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) -{ - uint16_t ret, data_port = 0xcfc | (reg & 0x02); - uint32_t cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - ret = inw(data_port); - sti(); - return ret; -} - - -uint32_t -pci_readl(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg) -{ - uint32_t ret, cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - ret = inl(0xcfc); - sti(); - return ret; -} - - -void -pci_writeb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t val) -{ - uint16_t data_port = 0xcfc | (reg & 0x03); - uint32_t cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - outb(data_port, val); - sti(); -} - - -void -pci_writew(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t val) -{ - uint16_t data_port = 0xcfc | (reg & 0x02); - uint32_t cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - outw(data_port, val); - sti(); -} - - -void -pci_writel(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val) -{ - uint32_t cf8 = pci_cf8(bus, dev, func, reg); - cli(); - outl(0xcf8, cf8); - outl(0xcfc, val); - sti(); -} diff --git a/lib/wlib.h b/lib/wlib.h deleted file mode 100644 index 02664eb..0000000 --- a/lib/wlib.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box Probing Tools distribution. - * - * Definitions for common functions for Watcom C-based tools. - * - * - * - * Authors: RichardG, - * - * Copyright 2021 RichardG. - * - */ -#ifndef WLIB_H -# define WLIB_H -#include - -#pragma pack(push, 0) -/* Convenience type for breaking a dword value down into words and bytes. */ -typedef union { - uint8_t u8[4]; - uint16_t u16[2]; - uint32_t u32; -} multi_t; -#pragma pack(pop) - - -/* Inline assembly functions. */ -void cli(); -#pragma aux cli = "cli"; -void sti(); -#pragma aux sti = "sti"; - -uint8_t inb(uint16_t port); -#pragma aux inb = "in al, dx" parm [dx] value [al]; -void outb(uint16_t port, uint8_t data); -#pragma aux outb = "out dx, al" parm [dx] [al]; -uint16_t inw(uint16_t port); -#pragma aux inw = "in ax, dx" parm [dx] value [ax]; -void outw(uint16_t port, uint16_t data); -#pragma aux outw = "out dx, ax" parm [dx] [ax]; -#ifdef M_I386 -uint32_t inl(uint16_t port); -# pragma aux inl = "in eax, dx" parm [dx] value [eax]; -void outl(uint16_t port, uint32_t data); -# pragma aux outl = "out dx, eax" parm [dx] [eax]; -#else -/* Some manual prefixing trickery to perform 32-bit I/O and access - the extended part of EAX in real mode. Exchanging is necessary - due to Watcom ignoring the order registers are specified in... */ -uint32_t inl(uint16_t port); -# pragma aux inl = "db 0x66" "in ax, dx" /* in eax, dx */ \ - "mov cx, ax" \ - "db 0x66, 0xc1, 0xe8, 0x10" /* shr eax, 16 */ \ - "xchg ax, cx" \ - parm [dx] \ - value [ax cx]; -void outl(uint16_t port, uint32_t data); -# pragma aux outl = "xchg ax, cx" \ - "db 0x66, 0xc1, 0xe0, 0x10" /* shl eax, 16 */ \ - "mov ax, cx" \ - "db 0x66" "out dx, ax" /* out dx, eax */ \ - parm [dx] [ax cx] \ - modify [ax cx]; -#endif - -/* Comparator functions. */ -extern int comp_ui8(const void *elem1, const void *elem2); - -/* PCI I/O functions. */ -extern uint32_t pci_cf8(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); -extern uint8_t pci_readb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); -extern uint16_t pci_readw(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); -extern uint32_t pci_readl(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg); -extern void pci_writeb(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint8_t val); -extern void pci_writew(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint16_t val); -extern void pci_writel(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val); - -#endif diff --git a/pcireg/Makefile b/pcireg/Makefile new file mode 100644 index 0000000..eb8a549 --- /dev/null +++ b/pcireg/Makefile @@ -0,0 +1,22 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Makefile for compiling C-based tools with Watcom. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +SYSTEM = DOS +OBJS = pcireg.obj clib.obj +DEST = PCIREG.EXE + +!include ../clib/watcom.mk diff --git a/pcireg/Makefile.uefi b/pcireg/Makefile.uefi new file mode 100644 index 0000000..21f3afa --- /dev/null +++ b/pcireg/Makefile.uefi @@ -0,0 +1,21 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box Probing Tools distribution. +# +# Makefile for compiling C-based tools with POSIX-UEFI. +# +# +# +# Authors: RichardG, +# +# Copyright 2021 RichardG. +# + +export OBJS = pcireg.o clib.o +export DEST = PCIREG.EFI + +include ../clib/uefi.mk diff --git a/pcireg/PCIIDS.BIN b/pcireg/PCIIDS.BIN index d7dd273..efbfbc9 100644 Binary files a/pcireg/PCIIDS.BIN and b/pcireg/PCIIDS.BIN differ diff --git a/pcireg/PCIREG.EFI b/pcireg/PCIREG.EFI new file mode 100644 index 0000000..ff9f06b Binary files /dev/null and b/pcireg/PCIREG.EFI differ diff --git a/pcireg/PCIREG.EXE b/pcireg/PCIREG.EXE index 0fcd7bc..0c0ca3b 100644 Binary files a/pcireg/PCIREG.EXE and b/pcireg/PCIREG.EXE differ diff --git a/pcireg/README.md b/pcireg/README.md index 3d6a254..e5efeda 100644 --- a/pcireg/README.md +++ b/pcireg/README.md @@ -1,6 +1,6 @@ pcireg ====== -DOS tool for reading, writing and dumping PCI configuration space registers; scanning the PCI bus; and more. +DOS and UEFI tool for reading, writing and dumping PCI configuration space registers; scanning the PCI bus; and more. Usage ----- @@ -31,5 +31,11 @@ Register dumps are saved to PCIbbddf.BIN where bb=bus, dd=device, f=function. Building -------- -* **Windows:** Run `build.bat` from an OpenWatcom "Build Environment" command prompt. -* **Linux:** Run `./build.sh` with OpenWatcom tools present in `$PATH`. +### DOS target: + +* **Windows:** Run `wmake` from an OpenWatcom "Build Environment" command prompt. +* **Linux:** Run `wmake` with OpenWatcom tools present in `$PATH`. + +### UEFI target: + +* **Linux:** Run `make -f Makefile.uefi ARCH=x86_64` with a GCC toolchain installed. diff --git a/pcireg/build.bat b/pcireg/build.bat deleted file mode 100644 index 398911f..0000000 --- a/pcireg/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -..\lib\build_watcom_dos.bat pcireg.c ..\lib\wlib.c diff --git a/pcireg/build.sh b/pcireg/build.sh deleted file mode 100644 index 3d42296..0000000 --- a/pcireg/build.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec ../lib/build_watcom_dos.sh pcireg.c ../lib/wlib.c diff --git a/pcireg/pciids.py b/pcireg/pciids.py index c6d3511..42299c1 100644 --- a/pcireg/pciids.py +++ b/pcireg/pciids.py @@ -97,7 +97,7 @@ def main(): # Enumerate vendor IDs. print('Enumerating vendors...') - for vendor_id in sorted(vendor_devices_offset): + for vendor_id in sorted(pciutil._pci_vendors): # Look up vendor ID. vendor = pciutil.clean_vendor(pciutil._pci_vendors.get(vendor_id, '')).encode('cp437', 'ignore')[:256] @@ -115,7 +115,7 @@ def main(): devices_offset = vendor_devices_offset.get(vendor_id, None) if devices_offset == None: devices_offset = 0xffffffff - if string_db_pos != 0xffffffff and devices_offset != 0xffffffff: + if string_db_pos != 0xffffffff or devices_offset != 0xffffffff: vendor_db += struct.pack('> 16) & 0xff, pci_subclass & 0xff, string_db_pos) + subclass_db += struct.pack('> 8) & 0xff, pci_subclass & 0xff, string_db_pos) subclass_has_termination = pci_subclass == 0xffff # Enumerate progif IDs. diff --git a/pcireg/pcireg.c b/pcireg/pcireg.c index cee05ad..d9d1634 100644 --- a/pcireg/pcireg.c +++ b/pcireg/pcireg.c @@ -19,15 +19,20 @@ * │ garbage, please tell your editor to open this file as UTF-8. │ * └──────────────────────────────────────────────────────────────┘ */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "wlib.h" +#ifdef __POSIX_UEFI__ +# include +#else +# include +# include +# include +# include +# include +# include +# ifdef __WATCOMC__ +# include +# endif +#endif +#include "clib.h" static const char *command_flags[] = { @@ -74,44 +79,46 @@ static const char *devsel[] = { }; -static struct videoconfig vc; -static union REGPACK rp; /* things break if this is not a global variable... */ +#ifdef __WATCOMC__ +static union REGPACK rp; +#endif +static int term_width; static FILE *pciids_f = NULL; #pragma pack(push, 0) -static struct { +static struct PACKED { uint32_t device_db_offset, - subdevice_db_offset, + subdevice_db_offset, class_db_offset, subclass_db_offset, progif_db_offset, string_db_offset; } pciids_header; -static struct { +static struct PACKED { uint16_t vendor_id; uint32_t devices_offset, - string_offset; + string_offset; } pciids_vendor; -static struct { +static struct PACKED { uint16_t device_id; uint32_t subdevices_offset, string_offset; } pciids_device; -static struct { +static struct PACKED { uint16_t subvendor_id, subdevice_id; uint32_t string_offset; } pciids_subdevice; -static struct { +static struct PACKED { uint8_t class_id; uint32_t string_offset; } pciids_class; -static struct { +static struct PACKED { uint8_t class_id, subclass_id; uint32_t string_offset; } pciids_subclass; -static struct { +static struct PACKED { uint8_t class_id, subclass_id, progif_id; @@ -119,6 +126,7 @@ static struct { } pciids_progif; +# if defined(__WATCOMC__) && !defined(M_I386) typedef struct { uint8_t bus, dev; struct { @@ -134,6 +142,7 @@ typedef struct { irq_routing_entry_t entry[1]; }; } irq_routing_table_t; +# endif #pragma pack(pop) @@ -160,6 +169,8 @@ static char * pciids_read_string(uint32_t offset) { uint8_t length, *buf; + uint32_t sum; + int i; /* Return nothing if the string offset is invalid. */ if (offset == 0xffffffff) @@ -170,7 +181,7 @@ pciids_read_string(uint32_t offset) return NULL; /* Seek to string offset. */ - fseek(pciids_f, pciids_header.string_db_offset + offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.string_db_offset + offset); /* Read string length, and return nothing if it's an empty string. */ fread(&length, sizeof(length), 1, pciids_f); @@ -198,7 +209,7 @@ pciids_find_vendor(uint16_t vendor_id) return 0; /* Seek to vendor database. */ - fseek(pciids_f, sizeof(pciids_header), SEEK_SET); + fseek_to(pciids_f, sizeof(pciids_header)); /* Read vendor entries until the ID is matched or overtaken. */ do { @@ -233,7 +244,7 @@ pciids_get_device(uint16_t device_id) return NULL; /* Seek to device database entries for the established vendor. */ - fseek(pciids_f, pciids_header.device_db_offset + pciids_vendor.devices_offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.device_db_offset + pciids_vendor.devices_offset); /* Read device entries until the ID is matched or overtaken. */ do { @@ -260,7 +271,7 @@ pciids_get_subdevice(uint16_t subvendor_id, uint16_t subdevice_id) return NULL; /* Seek to subdevice database entries for the established subvendor. */ - fseek(pciids_f, pciids_header.subdevice_db_offset + pciids_device.subdevices_offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.subdevice_db_offset + pciids_device.subdevices_offset); /* Read subdevice entries until the ID is matched or overtaken. */ do { @@ -285,7 +296,7 @@ pciids_get_class(uint8_t class_id) return NULL; /* Seek to class database. */ - fseek(pciids_f, pciids_header.class_db_offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.class_db_offset); /* Read class entries until the ID is matched or overtaken. */ do { @@ -310,7 +321,7 @@ pciids_get_subclass(uint8_t class_id, uint8_t subclass_id) return NULL; /* Seek to subclass database. */ - fseek(pciids_f, pciids_header.subclass_db_offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.subclass_db_offset); /* Read subclass entries until the ID is matched or overtaken. */ do { @@ -335,7 +346,7 @@ pciids_get_progif(uint8_t class_id, uint8_t subclass_id, uint8_t progif_id) return NULL; /* Seek to programming interface database. */ - fseek(pciids_f, pciids_header.progif_db_offset, SEEK_SET); + fseek_to(pciids_f, pciids_header.progif_db_offset); /* Read programming interface entries until the ID is matched or overtaken. */ do { @@ -355,7 +366,7 @@ pciids_get_progif(uint8_t class_id, uint8_t subclass_id, uint8_t progif_id) static int dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) { - int i, width, infobox, flags, bar_id; + int i, width, flags, bar_id; char buf[13]; uint8_t cur_reg, regs[256], dev_type, bar_reg; multi_t reg_val; @@ -367,6 +378,9 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) /* Generate dump file name. */ sprintf(buf, "PCI%02X%02X%d.BIN", bus, dev, func); + /* Get terminal size. */ + term_width = term_get_size_x(); + /* Size character '.' indicates a quiet dump for scan_bus. */ if (sz != '.') { /* Print banner message. */ @@ -378,7 +392,7 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) switch (sz) { case 'd': case 'l': - width = 68; /* width for register + infobox display */ + width = 40; for (i = 0x0; i <= 0xf; i += 4) { /* Add spacing at the halfway point. */ if (i == 0x8) @@ -388,7 +402,7 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) break; case 'w': - width = 72; + width = 44; for (i = 0x0; i <= 0xf; i += 2) { if (i == 0x8) putchar(' '); @@ -397,7 +411,7 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) break; default: - width = 80; + width = 52; for (i = 0x0; i <= 0xf; i++) { if (i == 0x8) putchar(' '); @@ -406,26 +420,12 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) break; } - /* Get terminal size. */ - _getvideoconfig(&vc); - - /* Print top of infobox if we're doing an infobox. */ - infobox = (start_reg < 0x3c) && (vc.numtextcols >= width); - if (infobox) { - printf(" ┌"); - for (i = 0; i < 24; i++) - putchar('─'); - putchar('┐'); - if (vc.numtextcols > width) - putchar('\n'); - } else { + /* Move on to the next line if the terminal didn't already do that for us. */ + if (width < term_width) putchar('\n'); - } } else { /* Print dump file name now. */ printf("Dumping registers to %s", buf); - - infobox = 0; } cur_reg = 0; @@ -498,229 +498,10 @@ dump_regs(uint8_t bus, uint8_t dev, uint8_t func, uint8_t start_reg, char sz) cur_reg += 4; } while (cur_reg & 0x0f); - /* Print infobox line if we're doing an infobox. */ - if (infobox) { - /* Print left line, unless this is the bottom row. */ - if (cur_reg) - printf(" │ "); - - /* Generate infobox lines, always checking if we have read the corresponding register(s). */ - switch (cur_reg) { - case 0x10: - /* Print class ID. */ - if (start_reg < 0x0c) - printf(" Class: %02X Base ", regs[0x0b]); - else - goto blank; - break; - - case 0x20: - /* Print subclass ID. */ - if (start_reg < 0x0c) - printf(" %02X Sub ", regs[0x0a]); - else - goto blank; - break; - - case 0x30: - /* Print programming interface ID. */ - if (start_reg < 0x0c) - printf(" %02X ProgIntf", regs[0x09]); - else - goto blank; - break; - - case 0x40: - flags = (start_reg < 0x02) | ((start_reg < 0x2e) << 1); - if (flags) { - printf("Vendor ID: "); - - /* Print vendor ID. */ - if (flags & 1) - printf("%04X", *((uint16_t *) ®s[0x00])); - else - printf("----"); - - /* Print subvendor ID. */ - if (flags & 2) - printf(" (%04X)", *((uint16_t *) ®s[0x2c])); - else - printf(" (----)"); - } else { - goto blank; - } - break; - - case 0x50: - flags = (start_reg < 0x04) | ((start_reg < 0x30) << 1); - if (flags) { - printf("Device ID: "); - - /* Print device ID. */ - if (flags & 1) - printf("%04X", *((uint16_t *) ®s[0x02])); - else - printf("----"); - - /* Print subdevice ID. */ - if (flags & 2) - printf(" (%04X)", *((uint16_t *) ®s[0x2e])); - else - printf(" (----)"); - } else { - goto blank; - } - break; - - case 0x60: - /* Print revision. */ - if (start_reg < 0x09) - printf(" Revision: %02X ", regs[0x08]); - else - goto blank; - break; - - case 0x70: - /* No IRQ on bridges. */ - if (regs[0x0e] & 0x7f) - goto blank; - - flags = regs[0x3c] && (regs[0x3c] != 0xff); - flags |= (regs[0x3d] && (regs[0x3d] != 0xff)) << 1; - if (flags) { - printf(" IRQ: "); - - /* Print IRQ number. */ - if (flags & 1) - printf("%2d", regs[0x3c] & 15); - else - printf("--"); - - /* Print INTx# line. */ - if (flags & 2) - printf(" (INT%c) ", '@' + (regs[0x3d] & 15)); - else - printf(" "); - } else { - goto blank; - } - break; - - case 0x80: - /* Print separator for the BAR section. */ -blank: - printf(" "); - break; - - case 0x90: - case 0xa0: - case 0xb0: - case 0xc0: - case 0xd0: - case 0xe0: - /* We must know the device type before printing BARs. */ - if (start_reg > 0x0e) - goto blank; - - /* Determine device type and current BAR register. */ - dev_type = regs[0x0e] & 0x7f; - bar_reg = (cur_reg >> 2) - 0x14; - - /* Bridges have special BAR2+ handling. */ - if ((dev_type == 0x01) && (bar_reg > 0x14)) { - /* Print bridge I/O and memory ranges. */ - switch (bar_reg) { - case 0x18: - if (start_reg < 0x1d) - printf(" Brdg I/O: %X000-%XFFF ", regs[0x1c] >> 4, regs[0x1d] >> 4); - else - goto blank; - break; - - case 0x1c: - if (start_reg < 0x21) - printf(" Brdg Mem: %03X00000- ", *((uint16_t *) ®s[0x20]) >> 4); - else - goto blank; - break; - - case 0x20: - if (start_reg < 0x21) - printf(" %03XFFFFF ", *((uint16_t *) ®s[0x22]) >> 4); - else - goto blank; - break; - - default: - goto blank; - } - break; - } else if (dev_type > 0x01) { - /* We don't parse CardBus bridges or other header types. */ - goto blank; - } - - /* Print BAR0-5 for regular devices, or BAR0-1 for bridges. */ - reg_val.u32 = *((uint32_t *) ®s[bar_reg]); - if ((start_reg <= bar_reg) && reg_val.u32 && (reg_val.u32 != 0xffffffff)) { - bar_id = (bar_reg - 0x10) >> 2; - if (reg_val.u8[0] & 0x01) - printf("I/O BAR %d: %04X ", bar_id, reg_val.u16[0] & 0xfffc); - else - printf("Mem BAR %d: %04X%04X ", bar_id, reg_val.u16[1], reg_val.u16[0] & 0xfff0); - } else { - goto blank; - } - break; - - case 0xf0: - /* Print expansion ROM BAR. */ - switch (regs[0x0e] & 0x7f) { - case 0x00: - if (start_reg < 0x31) - reg_val.u32 = *((uint32_t *) ®s[0x30]); - else - reg_val.u32 = 0; - break; - - case 0x01: - if (start_reg < 0x39) - reg_val.u32 = *((uint32_t *) ®s[0x38]); - else - reg_val.u32 = 0; - break; - - default: - reg_val.u32 = 0; - break; - } - if (reg_val.u32 && (reg_val.u32 != 0xffffffff)) - printf(" Exp ROM: %04X%04X ", reg_val.u16[1], reg_val.u16[0]); - else - goto blank; - break; - - case 0x00: - /* Print bottom of infobox. */ - printf(" └"); - for (i = 0; i < 24; i++) - printf("─"); - printf("\xd9"); - if (vc.numtextcols > 80) - printf("\n"); - break; - } - - /* Print right line, unless this is the bottom row. */ - if (cur_reg) - printf(" │"); - + if (sz != '.') { /* Move on to the next line if the terminal didn't already do that for us. */ - if (vc.numtextcols > width) - printf("\n"); - } else if (sz != '.') { - /* Move on to the next line. */ - printf("\n"); + if (width < term_width) + putchar('\n'); } } while (cur_reg); @@ -759,7 +540,7 @@ blank: static int -scan_bus(uint8_t bus, int nesting, char dump, FILE *f, char *buf) +scan_bus(uint8_t bus, int nesting, char dump, char *buf) { int i, j, count, last_count, children; char *temp; @@ -787,11 +568,11 @@ scan_bus(uint8_t bus, int nesting, char dump, FILE *f, char *buf) if (dev_id.u32 && (dev_id.u32 != 0xffffffff)) { /* Clear vendor/device name buffer while adding nested bus spacing if required. */ if (nesting) { - j = (nesting << 1) - 1; - memset(buf, ' ', j); - buf[j - 1] = '└'; - buf[j] = '─'; - buf[j + 1] = '\0'; + j = (nesting << 1) - 2; + for (i = 0; i < j; i++) + buf[i] = ' '; + buf[i] = '\0'; + sprintf(&buf[strlen(buf)], "└─"); } else { buf[0] = '\0'; } @@ -831,7 +612,7 @@ scan_bus(uint8_t bus, int nesting, char dump, FILE *f, char *buf) strcat(buf, "[Unknown] "); unknown_device: /* Look up class ID. */ - temp = pciids_get_class(dev_rev_class.u16[1]); + temp = pciids_get_subclass(dev_rev_class.u8[3], dev_rev_class.u8[2]); if (temp) { /* Add class name to buffer. */ sprintf(&buf[strlen(buf)], "[%s]", temp); @@ -843,52 +624,41 @@ unknown_device: /* Look up class ID. */ } /* Limit buffer to screen width, then print it with the revision ID. */ - i = vc.numtextcols - strlen(buf) - 24; + i = term_width - strlen(buf) - 24; if (i >= 9) { sprintf(&buf[strlen(buf)], " (rev %02X)", dev_rev_class.u8[0]); } else { if (i >= 5) strcat(buf, " "); else if (i < 4) - strcpy(&buf[vc.numtextcols - 32], "... "); + strcpy(&buf[term_width - 32], "... "); sprintf(&buf[strlen(buf)], "(%02X)", dev_rev_class.u8[0]); } printf(buf); /* Move on to the next line if the terminal didn't already do that for us. */ - if (vc.numtextcols > (strlen(buf) + 24)) + if (term_width > (strlen(buf) + 24)) putchar('\n'); - if (nesting && count) { - /* Get the current cursor position. */ - rp.h.ah = 0x03; - rp.h.bh = 0x00; - intr(0x10, &rp); - row = rp.h.dh; - column = rp.h.dl; - - /* Rectify previous nesting indicator. */ - rp.h.ah = 0x02; - rp.h.dl = 22 + (nesting << 1); - rp.h.dh -= 2; - if (children > rp.h.dh) - children = rp.h.dh; + /* Rectify previous nesting indicator when nesting buses. */ + if (nesting && count && term_get_cursor_pos(&column, &row)) { + i = 22 + (nesting << 1); + j = row - 2; + if (children > j) + children = j; while (children) { - intr(0x10, &rp); - putchar('│'); + term_set_cursor_pos(i, j); + printf("│"); children--; - rp.h.dh--; + j--; } - if (rp.h.dh != 0xff) { - intr(0x10, &rp); - putchar('├'); + if (j != 0xff) { + term_set_cursor_pos(i, j); + printf("├"); } /* Restore cursor position. */ - rp.h.ah = 0x02; - rp.h.dh = row; - rp.h.dl = column; - intr(0x10, &rp); + term_set_cursor_pos(column, row); } /* Dump registers if requested. */ @@ -922,7 +692,7 @@ unknown_device: /* Look up class ID. */ #endif /* Scan the secondary bus. */ - children = scan_bus(new_bus, nesting + 1, dump, f, buf); + children = scan_bus(new_bus, nesting + 1, dump, buf); count += children; } else { children = 0; @@ -943,27 +713,24 @@ scan_buses(char dump) { int i; char *buf; - FILE *f; /* Initialize buffers. */ buf = malloc(1024); memset(buf, 0, 1024); /* Get terminal size. */ - _getvideoconfig(&vc); + term_width = term_get_size_x(); /* Print header. */ - printf("Bus Dev Fun [Vend:Dev ] Device\n"); - for (i = 0; i < vc.numtextcols; i++) - putchar('─'); + printf("Bus Dev Fun [VeID:DeID] Device\n"); + for (i = 0; i < term_width; i++) + printf("─"); /* Scan the root bus. */ - scan_bus(0, 0, dump, f, buf); + scan_bus(0, 0, dump, buf); /* Clean up. */ free(buf); - if (f) - fclose(f); return 0; } @@ -978,9 +745,9 @@ info_flags_helper(uint16_t bitfield, const char **table) /* Check each bit. */ j = 0; for (i = 0; i < 16; i++) { - /* Ignore if there is no table entry. */ - if (!table[i]) - continue; + /* Ignore if there is no table entry. */ + if (!table[i]) + continue; /* Print flag name in [brackets] if set. */ if (bitfield & (1 << i)) @@ -988,11 +755,11 @@ info_flags_helper(uint16_t bitfield, const char **table) else printf(" %s ", table[i]); - /* Add line break and indentation after the 7th item. */ - if (++j == 7) { - printf("\n "); - j = 0; - } + /* Add line break and indentation after the 7th item. */ + if (++j == 7) { + printf("\n "); + j = 0; + } } } @@ -1117,7 +884,7 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) printf("\n\nRevision: %02X", reg_val.u8[0]); /* Print class ID. */ - printf("\n\nClass: [%02X] ", reg_val.u8[3]); + printf("\nClass: [%02X] ", reg_val.u8[3]); /* Print class name if found. */ temp = pciids_get_class(reg_val.u8[3]); @@ -1129,7 +896,7 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) } /* Print subclass ID. */ - printf("\n [%02X] "); + printf("\n [%02X] ", reg_val.u8[2]); /* Print subclass name if found. */ temp = pciids_get_subclass(reg_val.u8[3], reg_val.u8[2]); @@ -1141,7 +908,7 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) } /* Print programming interface ID. */ - printf("\n [%02X] "); + printf("\n [%02X] ", reg_val.u8[1]); /* Print programming interface name if found. */ temp = pciids_get_progif(reg_val.u8[3], reg_val.u8[2], reg_val.u8[1]); @@ -1152,27 +919,61 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) printf("[Unknown]"); } + /* Read latency, grant and interrupt line. */ + reg_val.u32 = pci_readl(bus, dev, func, 0x3c); + + /* Print interrupt if present. */ + if (reg_val.u16[0] && (reg_val.u16[0] != 0xffff)) + printf("\nInterrupt: INT%c (IRQ %d)", '@' + (reg_val.u8[1] & 15), reg_val.u8[0] & 15); + + /* Print latency and grant if available. */ + if ((header_type & 0x7f) == 0x00) { + printf("\nMin Grant: %.0f us at 33 MHz", reg_val.u8[2] * 0.25); + printf("\nMax Latency: %.0f us at 33 MHz", reg_val.u8[3] * 0.25); + } + /* Read and print BARs. */ for (i = 0; i < num_bars; i++) { - if (i == 0) - putchar('\n'); + if (i == 0) + putchar('\n'); - /* Read BAR. */ - reg_val.u32 = pci_readl(bus, dev, func, 0x10 + (i << 2)); + /* Read BAR. */ + reg_val.u32 = pci_readl(bus, dev, func, 0x10 + (i << 2)); - /* Move on to the next BAR if this one doesn't appear to be valid. */ - if (!reg_val.u32 || (reg_val.u32 == 0xffffffff)) - continue; + /* Move on to the next BAR if this one doesn't appear to be valid. */ + if (!reg_val.u32 || (reg_val.u32 == 0xffffffff)) + continue; - /* Print BAR index. */ - printf("\nBAR %d: ", i); + /* Print BAR index. */ + printf("\nBAR %d: ", i); - /* Print BAR type and address. */ - if (i & 1) - printf("I/O at %04X", reg_val.u16[0] & 0xfffc); - else - printf("Memory at %04X%04X", reg_val.u16[1], reg_val.u16[0] & 0xfff0); + /* Print BAR type, address and properties. */ + if (reg_val.u8[0] & 1) { + printf("I/O at %04X", reg_val.u16[0] & 0xfffc); + } else { + printf("Memory at %04X%04X (", reg_val.u16[1], reg_val.u16[0] & 0xfff0); + switch (reg_val.u8[0] & 0x06) { + case 0x00: + printf("32-bit"); + break; + case 0x02: + printf("below 1 MB"); + break; + + case 0x04: + printf("64-bit"); + break; + + case 0x06: + printf("invalid location"); + break; + } + printf(", "); + if (!(reg_val.u8[0] & 0x08)) + printf("not "); + printf("prefetchable)"); + } } printf("\n"); @@ -1181,6 +982,7 @@ dump_info(uint8_t bus, uint8_t dev, uint8_t func) } +#if defined(__WATCOMC__) && !defined(M_I386) static int comp_irq_routing_entry(const void *elem1, const void *elem2) { @@ -1240,7 +1042,7 @@ retry_buf: } /* Get terminal size. */ - _getvideoconfig(&vc); + term_width = term_get_size_x(); /* Start output according to the selected mode. */ if (mode == '8') { @@ -1321,7 +1123,7 @@ retry_buf: printf("┌ Location ─┐┌ INT Lines ┐┌ Steerable IRQs ───────── (INTA=1 B=2 C=4 D=8) ┐\n"); printf("│Slt Bus Dev││A1 B2 C3 D4││ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15│\n"); printf("┴───────────┴┴───────────┴┴───────────────────────────────────────────────┴"); - for (i = 75; i < vc.numtextcols; i++) + for (i = 75; i < term_width; i++) putchar('─'); } @@ -1414,6 +1216,7 @@ next_entry: return 0; } +#endif static int @@ -1454,7 +1257,7 @@ write_reg(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, char *val) case 1: case 2: /* Byte input value. */ - sscanf(val, "%" SCNx8, ®_val.u8[0]); + parse_hex_u8(val, ®_val.u8[0]); /* Print banner message. */ printf("Writing %02X to PCI bus %02X device %02X function %d register [%02X]\n", @@ -1479,7 +1282,7 @@ write_reg(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, char *val) case 3: case 4: /* Word input value. */ - sscanf(val, "%" SCNx16, ®_val.u16[0]); + parse_hex_u16(val, ®_val.u16[0]); /* Print banner message. */ printf("Writing %04X to PCI bus %02X device %02X function %d registers [%02X:%02X]\n", @@ -1505,7 +1308,7 @@ write_reg(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, char *val) default: /* Dword input value. */ - sscanf(val, "%" SCNx32, ®_val.u32); + parse_hex_u32(val, ®_val.u32); /* Print banner message. */ printf("Writing %04X%04X to PCI bus %02X device %02X function %d registers [%02X:%02X]\n", @@ -1538,40 +1341,45 @@ int main(int argc, char **argv) { int hexargc, i; - char *ch, nonhex; + char *ch; uint8_t hexargv[8], bus, dev, func, reg; uint32_t cf8; +#ifdef __WATCOMC__ /* Disable stdout buffering. */ setbuf(stdout, NULL); +#endif /* Print usage if there are too few parameters or if the first one looks invalid. */ if ((argc <= 1) || (strlen(argv[1]) < 2) || ((argv[1][0] != '-') && (argv[1][0] != '/'))) { usage: printf("Usage:\n"); printf("\n"); - printf("PCIREG -s [-d]\n"); + printf("%s -s [-d]\n", argv[0]); printf("∟ Display all devices on the PCI bus. Specify -d to dump registers as well.\n"); +#ifdef __WATCOMC__ printf("\n"); - printf("PCIREG -t [-8]\n"); + printf("%s -t [-8]\n", argv[0]); printf("∟ Display BIOS IRQ steering table. Specify -8 to display as 86Box code.\n"); +#endif printf("\n"); - printf("PCIREG -i [bus] device [function]\n"); + printf("%s -i [bus] device [function]\n", argv[0]); printf("∟ Show information about the specified device.\n"); printf("\n"); - printf("PCIREG -r [bus] device [function] register\n"); + printf("%s -r [bus] device [function] register\n", argv[0]); printf("∟ Read the specified register.\n"); printf("\n"); - printf("PCIREG -w [bus] device [function] register value\n"); + printf("%s -w [bus] device [function] register value\n", argv[0]); printf("∟ Write byte, word or dword to the specified register.\n"); printf("\n"); - printf("PCIREG {-d|-dw|-dl} [bus] device [function [register]]\n"); + printf("%s {-d|-dw|-dl} [bus] device [function [register]]\n", argv[0]); printf("∟ Dump registers as bytes (-d), words (-dw) or dwords (-dl). Optionally\n"); printf(" specify the register to start from (requires bus to be specified as well).\n"); printf("\n"); printf("All numeric parameters should be specified in hexadecimal (without 0x prefix).\n"); printf("{bus device function register} can be substituted for a single port CF8h dword.\n"); printf("Register dumps are saved to PCIbbddf.BIN where bb=bus, dd=device, f=function."); + term_finallinebreak(); return 1; } @@ -1600,16 +1408,19 @@ usage: return scan_buses(argv[2][1]); else return scan_buses('\0'); - } else if (argv[1][1] == 't') { + } +#if defined(__WATCOMC__) && !defined(M_I386) + else if (argv[1][1] == 't') { /* Steering table display only requires a single optional parameter. */ if ((argc >= 3) && (strlen(argv[2]) > 1)) return dump_steering_table(argv[2][1]); else return dump_steering_table('\0'); - } else if ((argc >= 3) && (strlen(argv[1]) > 1)) { + } +#endif + else if ((argc >= 3) && (strlen(argv[1]) > 1)) { /* Read second parameter as a dword. */ - nonhex = 0; - if (sscanf(argv[2], "%" SCNx32 "%c", &cf8, &nonhex) && !nonhex) { + if (parse_hex_u32(argv[2], &cf8)) { /* Initialize default bus/device/function/register values. */ bus = dev = func = reg = 0; @@ -1625,8 +1436,7 @@ usage: /* Read parameters until the end is reached or an invalid hex value is found. */ for (i = 3; (i < argc) && (i < (sizeof(hexargv) - 1)); i++) { - nonhex = 0; - if (!sscanf(argv[i], "%" SCNx8 "%s", &hexargv[hexargc++], &nonhex) || nonhex) + if (!parse_hex_u8(argv[i], &hexargv[hexargc++])) break; } } else { @@ -1705,6 +1515,7 @@ usage: break; default: + printf("unknown hexargc %d\n", hexargc); goto usage; } diff --git a/pcireg/pciutil.py b/pcireg/pciutil.py index 5e2e2d9..bab1541 100644 --- a/pcireg/pciutil.py +++ b/pcireg/pciutil.py @@ -15,13 +15,20 @@ # # Copyright 2021 RichardG. # -import re, urllib.request +import io, re, urllib.request clean_device_abbr = [ + # Generic patterns to catch extended abbreviations: "Abbreviated Terms (AT)" + ('([A-Z])[^\s]+ ([A-Z])[^\s]+ (?:\(|\[|\{|/)\\2\\3(?:$|\)|\]|\})', '\\2\\3'), + ('([A-Z])[^\s]+ ([A-Z])[^\s]+ ([A-Z])[^\s]+ (?:\(|\[|\{|/)\\2\\3\\4(?:$|\)|\]|\})', '\\2\\3\\4'), + ('([A-Z])[^\s]+ ([A-Z])[^\s]+ ([A-Z])[^\s]+ ([A-Z])[^\s]+ (?:\(|\[|\{|/)\\2\\3\\4\\5(?:$|\)|\]|\})', '\\2\\3\\4\\5'), + + # Manual patterns ('100Base-TX?', 'FE'), ('1000Base-T', 'GbE'), ('Accelerat(?:ion|or)', 'Accel.'), ('Alert on LAN', 'AoL'), + ('\((.+) applications?\)', '\\2'), # 8086:105e ('Chipset Family', 'Chipset'), ('Chipset Graphics', 'iGPU'), ('Connection', 'Conn.'), @@ -61,9 +68,11 @@ clean_device_abbr = [ ('Virtual Machine', 'VM'), ('Wake on LAN', 'WoL'), ('Wireless LAN', 'WLAN'), + + # Generic pattern to remove duplicate abbreviations: "AT (AT)" + ('([^ \(\[\{/]+) (?: |\(|\[|\{|/)\\2(?: |\)|\]|\})', '\\2'), ] clean_device_bit_pattern = re.compile('''( |^|\(|\[|\{|/)(?:([0-9]{1,4}) )?(?:(K)(?:ilo)?|(M)(?:ega)?|(G)(?:iga)?)bit( |$|\)|\]|\})''', re.I) -clean_device_doubleabbr_pattern = re.compile('''( |^|\(|\[|\{|/)([^ \(\[\{/]+) (?: |\(|\[|\{|/)\\2(?: |\)|\]|\})( |$|\)|\]|\})''') clean_device_suffix_pattern = re.compile(''' (?:Adapter|Card|Device|(?:Host )?Controller)( (?: [0-9#]+)?|$|\)|\]|\})''', re.I) clean_vendor_abbr_pattern = re.compile(''' \[([^\]]+)\]''') clean_vendor_suffix_pattern = re.compile(''' (?:Semiconductors?|(?:Micro)?electronics?|Interactive|Technolog(?:y|ies)|(?:Micro)?systems|Computer(?: works)?|Products|Group|and subsidiaries|of(?: America)?|Co(?:rp(?:oration)?|mpany)?|Inc|LLC|Ltd|GmbH|AB|AG|SA|(?:\(|\[|\{).*)$''', re.I) @@ -106,7 +115,6 @@ def clean_device(device, vendor=None): device = clean_device_bit_pattern.sub('\\1\\2\\3\\4\\5bit\\6', device) for pattern, replace in _clean_device_abbr_cache: device = pattern.sub(replace, device) - device = clean_device_doubleabbr_pattern.sub('\\1\\2\\3', device) device = clean_device_suffix_pattern.sub('\\1', device) # Remove duplicate vendor ID. @@ -144,6 +152,43 @@ def clean_vendor(vendor): # Remove duplicate spaces. return ' '.join(vendor.split()) +def download_compressed(url, skip_exts=[]): + """Downloads a file which may be available in compressed versions.""" + + # Try all files. + for ext, module_name in (('.xz', 'lzma'), ('.bz2', 'bz2'), ('.gz', 'gzip'), (None, None)): + # Skip extension if requested. + if ext in skip_exts: + continue + + # Import decompression module if required. + if module_name: + try: + module = __import__(module_name) + except: + continue + + # Connect to URL. + try: + f = urllib.request.urlopen(url + (ext or ''), timeout=30) + except: + # Move on to the next file if the connection failed. + continue + + # If this is uncompressed, return the file handle as is. + if not module_name: + return f + + # Decompress data into a BytesIO object. + try: + return io.BytesIO(module.decompress(f.read())) + except: + # Move on to the next file if decompression failed. + continue + + # No success with any files. + raise FileNotFoundError('All attempts to download "{0}" and variants thereof have failed'.format(url)) + def get_pci_id(vendor_id, device_id): """Get the PCI device vendor and name for vendor_id and device_id.""" @@ -163,7 +208,7 @@ def load_pci_db(): f = open('/usr/share/misc/pci.ids', 'rb') except: try: - f = urllib.request.urlopen('https://pci-ids.ucw.cz/v2.2/pci.ids', timeout=30) + f = download_compressed('https://pci-ids.ucw.cz/v2.2/pci.ids', ['.xz']) except: # No sources available. return diff --git a/pcireg/uefi/Makefile b/pcireg/uefi/Makefile new file mode 100644 index 0000000..d4bc02c --- /dev/null +++ b/pcireg/uefi/Makefile @@ -0,0 +1,112 @@ +# detect architecture +MYARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) +ifeq ($(ARCH),) +ARCH = $(MYARCH) +endif + +# get source files, generate object names +ifeq ($(SRCS),) +SRCS = $(wildcard *.c) $(wildcard *.S) +endif +TMP = $(SRCS:.c=.o) +OBJS2 = $(TMP:.S=.o) +CFLAGS += -fshort-wchar -fno-strict-aliasing -ffreestanding -fno-stack-protector -fno-stack-check -I. -I./uefi \ + -I/usr/include -I/usr/include/efi -I/usr/include/efi/protocol -I/usr/include/efi/$(ARCH) -D__$(ARCH)__ +ifeq ($(ARCH),x86_64) +CFLAGS += -DHAVE_USE_MS_ABI -mno-red-zone +endif + +# for libuefi.a +LIBSRCS = $(filter-out $(wildcard crt_*.c),$(wildcard *.c)) $(wildcard *.S) +TMP2 = $(LIBSRCS:.c=.o) +LIBOBJS2 = $(TMP2:.S=.o) + +# detect toolchain +ifeq ($(wildcard /usr/bin/clang),) +USE_GCC = 1 +endif +ifneq ($(USE_GCC),) +ifeq ($(ARCH),x86_64) +CFLAGS += -maccumulate-outgoing-args +endif +CFLAGS += -Wno-builtin-declaration-mismatch -fpic -fPIC +LDFLAGS += -nostdlib -shared -Bsymbolic -Luefi uefi/crt_$(ARCH).o +LIBS += -o $(TARGET).so -luefi -T uefi/elf_$(ARCH)_efi.lds +# see if we're cross-compiling +ifneq ($(ARCH),$(MYARCH)) +CC = $(ARCH)-elf-gcc +LD = $(ARCH)-elf-ld +OBJCOPY ?= $(ARCH)-elf-objcopy +else +CC = gcc +LD = ld +OBJCOPY ?= objcopy +endif +ifeq ($(ARCH),aarch64) +EFIARCH = pei-aarch64-little +else +EFIARCH = efi-app-$(ARCH) +endif +AR ?= ar +else +CFLAGS += --target=$(ARCH)-pc-win32-coff -Wno-builtin-requires-header -Wno-incompatible-library-redeclaration -Wno-long-long +LDFLAGS += -subsystem:efi_application -nodefaultlib -dll -entry:uefi_init uefi/*.o +LIBS = -out:$(TARGET) +CC = clang +LD = lld-link +OBJCOPY = true +endif + +# recipies +ifeq ($(wildcard uefi/Makefile),) +ALLTARGETS = crt_$(ARCH).o libuefi.a build +else +ALLTARGETS = uefi/crt_$(ARCH).o uefi/libuefi.a $(OBJS2) $(TARGET) +endif + +all: $(ALLTARGETS) $(EXTRA) + +uefi/libuefi.a: + @make --no-print-directory -C uefi libuefi.a USE_GCC=$(USE_GCC) ARCH=$(ARCH) + +libuefi.lib: $(LIBOBJS2) + +libuefi.a: $(LIBOBJS2) +ifneq ($(USE_GCC),) + @rm $@ 2>/dev/null || true + $(AR) -frsv $@ $(LIBOBJS2) >/dev/null +else + @true +endif + +$(TARGET): $(TARGET).so +ifneq ($(USE_GCC),) + @$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target $(EFIARCH) --subsystem=10 $^ $@ || echo target: $(EFIARCH) + @rm $(TARGET).so +endif + +$(TARGET).so: $(OBJS2) + $(LD) $(LDFLAGS) $^ $(LIBS) + @rm *.lib 2>/dev/null || true + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.S + $(CC) $(CFLAGS) -c $< -o $@ + +build: + @mkdir ../build ../build/uefi 2>/dev/null || true + @cp crt_$(ARCH).o ../build/uefi/crt0.o + @cp elf_$(ARCH)_efi.lds ../build/uefi/link.ld + @cp libuefi.a uefi.h ../build/uefi + +clean: + @rm $(TARGET) *.o *.a *.lib *.elf $(LIBOBJS2) 2>/dev/null || true + +distclean: clean +ifeq ($(wildcard uefi/Makefile),) + @rm -rf ../build 2>/dev/null || true +else + @rm uefi/*.o uefi/libuefi.a 2>/dev/null || true +endif diff --git a/pcireg/uefi/crt_aarch64.c b/pcireg/uefi/crt_aarch64.c new file mode 100644 index 0000000..f7ed6bf --- /dev/null +++ b/pcireg/uefi/crt_aarch64.c @@ -0,0 +1,232 @@ +/* + * 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 */ +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; +typedef uint64_t Elf64_Addr; +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base */ + +/* globals to store system table pointers */ +efi_handle_t IM = NULL; +efi_system_table_t *ST = NULL; +efi_boot_services_t *BS = NULL; +efi_runtime_services_t *RT = NULL; +efi_loaded_image_protocol_t *LIP = NULL; +#if USE_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap() +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " 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 + */ +int uefi_init ( + efi_handle_t image, efi_system_table_t *systab +#ifndef __clang__ + , uintptr_t ldbase, Elf64_Dyn *dyn +#endif +) { + efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID; + efi_shell_parameters_protocol_t *shp = NULL; + efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID; + efi_shell_interface_protocol_t *shi = NULL; + efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + efi_status_t status; + int argc = 0, i; + wchar_t **argv = NULL; +#if USE_UTF8 + int ret, 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; break; } + rel = (Elf64_Rel*) ((char *) rel + relent); + relsz -= relent; + } + } +#else + (void)i; +#endif + /* save EFI pointers and loaded image into globals */ + IM = image; + ST = systab; + BS = systab->BootServices; + RT = systab->RuntimeServices; + BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + /* get command line arguments */ + status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shp) { argc = shp->Argc; argv = shp->Argv; } + else { + /* if shell 2.0 failed, fallback to shell 1.0 interface */ + status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shi) { argc = shi->Argc; argv = shi->Argv; } + } + /* call main */ +#if USE_UTF8 + if(argc && argv) { + ret = (argc + 1) * (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, ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * 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 + return main(argc, argv); +#endif +} diff --git a/pcireg/uefi/crt_x86_64.c b/pcireg/uefi/crt_x86_64.c new file mode 100644 index 0000000..2597adf --- /dev/null +++ b/pcireg/uefi/crt_x86_64.c @@ -0,0 +1,235 @@ +/* + * 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 */ +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 */ + +/* 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; +#if USE_UTF8 +char *__argvutf8 = NULL; +#endif + +/* we only need one .o file, so use inline Assembly here */ +void bootstrap() +{ + __asm__ __volatile__ ( + /* call init in C */ + " .align 4\n" +#ifndef __clang__ + " .globl _start\n" + "_start:\n" + " 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 + */ +int 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; + wchar_t **argv = NULL; +#if USE_UTF8 + int ret, 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; break; } + 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" + ); + /* save EFI pointers and loaded image into globals */ + IM = image; + ST = systab; + BS = systab->BootServices; + RT = systab->RuntimeServices; + BS->HandleProtocol(image, &lipGuid, (void **)&LIP); + /* get command line arguments */ + status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shp) { argc = shp->Argc; argv = shp->Argv; } + else { + /* if shell 2.0 failed, fallback to shell 1.0 interface */ + status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(!EFI_ERROR(status) && shi) { argc = shi->Argc; argv = shi->Argv; } + } + /* call main */ +#if USE_UTF8 + if(argc && argv) { + ret = (argc + 1) * (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, ret, (void **)&__argvutf8); + if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; } + else { + s = __argvutf8 + argc * sizeof(uintptr_t); + *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t); + for(i = 0; i < argc; i++) { + *((uintptr_t*)(__argvutf8 + i * 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 + return main(argc, argv); +#endif +} diff --git a/pcireg/uefi/dirent.c b/pcireg/uefi/dirent.c new file mode 100644 index 0000000..320b190 --- /dev/null +++ b/pcireg/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); +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; +#if USE_UTF8 + __dirent.d_reclen = 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/pcireg/uefi/elf_aarch64_efi.lds b/pcireg/uefi/elf_aarch64_efi.lds new file mode 100644 index 0000000..836d982 --- /dev/null +++ b/pcireg/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/pcireg/uefi/elf_x86_64_efi.lds b/pcireg/uefi/elf_x86_64_efi.lds new file mode 100644 index 0000000..7be5902 --- /dev/null +++ b/pcireg/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/pcireg/uefi/qsort.c b/pcireg/uefi/qsort.c new file mode 100644 index 0000000..d6563c9 --- /dev/null +++ b/pcireg/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/pcireg/uefi/stat.c b/pcireg/uefi/stat.c new file mode 100644 index 0000000..017a4f8 --- /dev/null +++ b/pcireg/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/pcireg/uefi/stdio.c b/pcireg/uefi/stdio.c new file mode 100644 index 0000000..a9f80de --- /dev/null +++ b/pcireg/uefi/stdio.c @@ -0,0 +1,762 @@ +/* + * 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() +{ +#if USE_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; + int 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; + __buf->st_blocks = __blk_devs[i].bio->Media->LastBlock; + 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 == 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 == 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; + FILE *f = fopen(__filename, CL("r")); + if(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; +#if USE_UTF8 + wchar_t wcname[BUFSIZ]; +#endif + if(!__filename || !*__filename || !__modes || !*__modes) { + 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 = 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 = 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); + __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(!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 >= 0 && 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; + } + errno = 0; + ret = (FILE*)malloc(sizeof(FILE)); + if(!ret) return NULL; +#if USE_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') ? (EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE) : EFI_FILE_MODE_READ, + __modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0); + if(EFI_ERROR(status)) { +err: __stdio_seterrno(status); + free(ret); return NULL; + } + status = ret->GetInfo(ret, &infGuid, &fsiz, &info); + if(EFI_ERROR(status)) goto err; + if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) { + free(ret); errno = ENOTDIR; return NULL; + } + if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) { + free(ret); errno = EISDIR; return NULL; + } + if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END); + 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(__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(__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 == 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 == 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 == 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[19], pad, n; +#if !defined(USE_UTF8) || !USE_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, int); +#if USE_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')) { + arg = __builtin_va_arg(args, int); + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + i=18; + 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<18) { + while(i>18-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, long int); +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 +#if !defined(USE_UTF8) || !USE_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('.') : 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 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, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsnprintf(dst, BUFSIZ, fmt, args); +} + +int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsnprintf(dst, maxlen, fmt, args); +} + +int vprintf(const char_t* fmt, __builtin_va_list args) +{ + int ret; + wchar_t dst[BUFSIZ]; +#if USE_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, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vprintf(fmt, args); +} + +int vfprintf (FILE *__stream, const char_t *__format, __builtin_va_list args) +{ + wchar_t dst[BUFSIZ]; + char_t tmp[BUFSIZ]; + uintn_t ret, i; +#if USE_UTF8 + ret = vsnprintf(tmp, BUFSIZ, __format, args); + ret = mbstowcs(dst, tmp, BUFSIZ - 1); +#else + ret = vsnprintf(dst, BUFSIZ, __format, args); +#endif + if(ret < 1 || __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) { +#if !defined(USE_UTF8) || !USE_UTF8 + wcstombs((char*)&tmp, dst, BUFSIZ - 1); +#endif + __ser->Write(__ser, &ret, (void*)&tmp); + } else +#if USE_UTF8 + __stream->Write(__stream, &ret, (void*)&tmp); +#else + __stream->Write(__stream, &ret, (void*)&dst); +#endif + return ret; +} + +int fprintf (FILE *__stream, const char_t *__format, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, __format); + return vfprintf(__stream, __format, args); +} + +int getchar (void) +{ + efi_input_key_t key; + efi_status_t status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); + return EFI_ERROR(status) ? -1 : key.UnicodeChar; + +} + +int getchar_ifany (void) +{ + efi_input_key_t key; + efi_status_t status = BS->CheckEvent(ST->ConIn->WaitForKey); + if(!status) { + status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key); + return EFI_ERROR(status) ? -1 : key.UnicodeChar; + } + return 0; +} + +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/pcireg/uefi/stdlib.c b/pcireg/uefi/stdlib.c new file mode 100644 index 0000000..efd706d --- /dev/null +++ b/pcireg/uefi/stdlib.c @@ -0,0 +1,330 @@ +/* + * 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(); +static uintptr_t *__stdlib_allocs = NULL; +static uintn_t __stdlib_numallocs = 0; + +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; + uintn_t i; + /* this is so fucked up. UEFI firmware must keep track of allocated sizes internally, yet we must + * too, because realloc won't work otherwise... Why can't AllocatePool accept input addresses? */ + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2); + if(i == __stdlib_numallocs) { + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __stdlib_numallocs + 2, &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; + } + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; + 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; + uintn_t i; + if(!__ptr) return malloc(__size); + for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2); + if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; } + status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret); + if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; } + if(ret) { + 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]); + } + BS->FreePool((void*)__stdlib_allocs[i]); + __stdlib_allocs[i] = (uintptr_t)ret; + __stdlib_allocs[i + 1] = (uintptr_t)__size; + return ret; +} + +void free (void *__ptr) +{ + efi_status_t status; + uintn_t i; + 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; + 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; } + status = BS->FreePool(__ptr); + if(EFI_ERROR(status)) errno = ENOMEM; +} + +void abort () +{ + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_numallocs = 0; + __stdio_cleanup(); + BS->Exit(IM, EFI_ABORTED, 0, NULL); +} + +void exit (int __status) +{ + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_numallocs = 0; + __stdio_cleanup(); + BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL); +} + +int exit_bs() +{ + efi_status_t status; + efi_memory_descriptor_t *memory_map = NULL; + uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0; + if(__stdlib_allocs) + BS->FreePool(__stdlib_allocs); + __stdlib_numallocs = 0; + __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 - (__pwcs - orig)); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__pwcs = 0; + return __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 && (__s - orig + 4 < __n)) { + r = wctomb(__s, *__pwcs); + if(r < 0) return (size_t)-1; + __pwcs++; + __s += r; + } + *__s = 0; + return __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; +#if USE_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; +#if USE_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/pcireg/uefi/string.c b/pcireg/uefi/string.c new file mode 100644 index 0000000..3286e7b --- /dev/null +++ b/pcireg/uefi/string.c @@ -0,0 +1,258 @@ +/* + * 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 && 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 && n>0) { + if((ab) || (ba)) { + a+=n-1; b+=n-1; while(n-->0) *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++ = 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 && 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; + 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) +{ + if(src && dst) { + while(*src) {*dst++=*src++;} *dst=0; + } + return dst; +} + +char_t *strncpy(char_t *dst, const char_t *src, size_t n) +{ + const char_t *e = src+n; + if(src && dst && n>0) { + while(*src && src0) { + dst += strlen(dst); + while(*src && src0) { + do{if(*s1!=*s2){return *s1-*s2;}s1++;s2++;}while(*s1!=0 && s1 + +static struct tm __tm; + +/* from musl */ +uint64_t __year_to_secs(uint64_t year, int *is_leap) +{ + int y, cycles, centuries, leaps, rem; + + if (year-2ULL <= 136) { + y = year; + leaps = (y-68)>>2; + if (!((y-68)&3)) { + leaps--; + if (is_leap) *is_leap = 1; + } else if (is_leap) *is_leap = 0; + return 31536000*(y-70) + 86400*leaps; + } + + if (!is_leap) is_leap = &(int){0}; + cycles = (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 / 4U; + rem %= 4U; + *is_leap = !rem; + } + } + + leaps += 97*cycles + 24*centuries - *is_leap; + + return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; +} + +time_t __mktime_efi(efi_time_t *t) +{ + __tm.tm_year = t->Year + 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 int 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 = tm->tm_year, t; + int month = tm->tm_mon; + if (month >= 12 || month < 0) { + int adj = 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 += 86400LL * (tm->tm_mday-1); + t += 3600LL * tm->tm_hour; + t += 60LL * tm->tm_min; + 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/pcireg/uefi/uefi.h b/pcireg/uefi/uefi.h new file mode 100644 index 0000000..836281d --- /dev/null +++ b/pcireg/uefi/uefi.h @@ -0,0 +1,1420 @@ +/* + * 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_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* comment out this if you want to use wchar_t in your application */ +#define USE_UTF8 1 + +/* get these from the compiler */ +#ifndef _STDINT_H +#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; +#if USE_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 | a) +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR_OEM(a) (0xc000000000000000 | 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 +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, + 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 SourceSie, 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(); +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); + +#ifdef __cplusplus +} +#endif + +#endif /* _UEFI_H_ */ diff --git a/pcireg/uefi/unistd.c b/pcireg/uefi/unistd.c new file mode 100644 index 0000000..0ea6246 --- /dev/null +++ b/pcireg/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); +}