mirror of
https://github.com/86Box/probing-tools.git
synced 2026-02-21 09:05:34 -07:00
MOAC with build system overhaul (now makefiles), UEFI for pcireg, ACPI tool and other stuff
This commit is contained in:
18
.gitignore
vendored
18
.gitignore
vendored
@@ -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
|
||||
|
||||
BIN
acpi/ACPI.EXE
Normal file
BIN
acpi/ACPI.EXE
Normal file
Binary file not shown.
22
acpi/Makefile
Normal file
22
acpi/Makefile
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# Copyright 2021 RichardG.
|
||||
#
|
||||
|
||||
SYSTEM = DOS
|
||||
OBJS = acpi.obj clib.obj
|
||||
DEST = ACPI.EXE
|
||||
|
||||
!include ../clib/watcom.mk
|
||||
12
acpi/README.md
Normal file
12
acpi/README.md
Normal file
@@ -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`.
|
||||
139
acpi/acpi.c
Normal file
139
acpi/acpi.c
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
3
clib/README.md
Normal file
3
clib/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
clib
|
||||
====
|
||||
Not a probing tool. Common library for C-based tools.
|
||||
405
clib/clib.c
Normal file
405
clib/clib.c
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2021 RichardG.
|
||||
*
|
||||
*/
|
||||
#ifdef __POSIX_UEFI__
|
||||
# include <uefi.h>
|
||||
#else
|
||||
# include <inttypes.h>
|
||||
# include <stdint.h>
|
||||
# include <stdio.h>
|
||||
# include <string.h>
|
||||
# ifdef __WATCOMC__
|
||||
# include <dos.h>
|
||||
# include <graph.h>
|
||||
# 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
|
||||
}
|
||||
125
clib/clib.h
Normal file
125
clib/clib.h
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* 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
|
||||
25
clib/uefi.mk
Normal file
25
clib/uefi.mk
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
88
clib/watcom.mk
Normal file
88
clib/watcom.mk
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
22
cp437/Makefile
Normal file
22
cp437/Makefile
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# Copyright 2021 RichardG.
|
||||
#
|
||||
|
||||
SYSTEM = HOST
|
||||
OBJS = cp437.obj
|
||||
DEST = cp437
|
||||
|
||||
!include ../clib/watcom.mk
|
||||
@@ -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`.
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
..\lib\build_watcom_host.bat cp437.c
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
exec ../lib/build_watcom_host.sh 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;
|
||||
|
||||
@@ -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, <richardg867@gmail.com>
|
||||
::
|
||||
:: 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.
|
||||
)
|
||||
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
@@ -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, <richardg867@gmail.com>
|
||||
::
|
||||
:: 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.
|
||||
)
|
||||
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# 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
|
||||
116
lib/wlib.c
116
lib/wlib.c
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2021 RichardG.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#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();
|
||||
}
|
||||
83
lib/wlib.h
83
lib/wlib.h
@@ -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, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2021 RichardG.
|
||||
*
|
||||
*/
|
||||
#ifndef WLIB_H
|
||||
# define WLIB_H
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
22
pcireg/Makefile
Normal file
22
pcireg/Makefile
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# Copyright 2021 RichardG.
|
||||
#
|
||||
|
||||
SYSTEM = DOS
|
||||
OBJS = pcireg.obj clib.obj
|
||||
DEST = PCIREG.EXE
|
||||
|
||||
!include ../clib/watcom.mk
|
||||
21
pcireg/Makefile.uefi
Normal file
21
pcireg/Makefile.uefi
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
#
|
||||
# Copyright 2021 RichardG.
|
||||
#
|
||||
|
||||
export OBJS = pcireg.o clib.o
|
||||
export DEST = PCIREG.EFI
|
||||
|
||||
include ../clib/uefi.mk
|
||||
Binary file not shown.
BIN
pcireg/PCIREG.EFI
Normal file
BIN
pcireg/PCIREG.EFI
Normal file
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
..\lib\build_watcom_dos.bat pcireg.c ..\lib\wlib.c
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
exec ../lib/build_watcom_dos.sh pcireg.c ../lib/wlib.c
|
||||
@@ -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('<HII', vendor_id, devices_offset, string_db_pos)
|
||||
vendor_has_termination = vendor_id == 0xffff
|
||||
|
||||
@@ -156,7 +156,7 @@ def main():
|
||||
string_db_pos = 0xffffffff
|
||||
|
||||
# Add to subclass database.
|
||||
subclass_db += struct.pack('<BBI', (pci_subclass >> 16) & 0xff, pci_subclass & 0xff, string_db_pos)
|
||||
subclass_db += struct.pack('<BBI', (pci_subclass >> 8) & 0xff, pci_subclass & 0xff, string_db_pos)
|
||||
subclass_has_termination = pci_subclass == 0xffff
|
||||
|
||||
# Enumerate progif IDs.
|
||||
|
||||
521
pcireg/pcireg.c
521
pcireg/pcireg.c
@@ -19,15 +19,20 @@
|
||||
* │ garbage, please tell your editor to open this file as UTF-8. │
|
||||
* └──────────────────────────────────────────────────────────────┘
|
||||
*/
|
||||
#include <dos.h>
|
||||
#include <graph.h>
|
||||
#include <inttypes.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "wlib.h"
|
||||
#ifdef __POSIX_UEFI__
|
||||
# include <uefi.h>
|
||||
#else
|
||||
# include <inttypes.h>
|
||||
# include <malloc.h>
|
||||
# include <stdio.h>
|
||||
# include <stdint.h>
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
# ifdef __WATCOMC__
|
||||
# include <dos.h>
|
||||
# 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
112
pcireg/uefi/Makefile
Normal file
112
pcireg/uefi/Makefile
Normal file
@@ -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
|
||||
232
pcireg/uefi/crt_aarch64.c
Normal file
232
pcireg/uefi/crt_aarch64.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
/* 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
|
||||
}
|
||||
235
pcireg/uefi/crt_x86_64.c
Normal file
235
pcireg/uefi/crt_x86_64.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
/* 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
|
||||
}
|
||||
76
pcireg/uefi/dirent.c
Normal file
76
pcireg/uefi/dirent.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
63
pcireg/uefi/elf_aarch64_efi.lds
Normal file
63
pcireg/uefi/elf_aarch64_efi.lds
Normal file
@@ -0,0 +1,63 @@
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x0 : {
|
||||
_text = .;
|
||||
*(.text.head)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.srodata)
|
||||
*(.rodata*)
|
||||
. = ALIGN(16);
|
||||
}
|
||||
_etext = .;
|
||||
_text_size = . - _text;
|
||||
.dynamic : { *(.dynamic) }
|
||||
.data : ALIGN(4096)
|
||||
{
|
||||
_data = .;
|
||||
*(.sdata)
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data.*)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
|
||||
/* the EFI loader doesn't seem to like a .bss section, so we stick
|
||||
it all into .data: */
|
||||
. = ALIGN(16);
|
||||
_bss = .;
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
_bss_end = .;
|
||||
}
|
||||
|
||||
.rela.dyn : { *(.rela.dyn) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rela.data : { *(.rela.data) *(.rela.data*) }
|
||||
. = ALIGN(512);
|
||||
_edata = .;
|
||||
_data_size = . - _data;
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
. = ALIGN(4096);
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.rel.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
||||
76
pcireg/uefi/elf_x86_64_efi.lds
Normal file
76
pcireg/uefi/elf_x86_64_efi.lds
Normal file
@@ -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) }
|
||||
}
|
||||
154
pcireg/uefi/qsort.c
Normal file
154
pcireg/uefi/qsort.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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);*/
|
||||
}
|
||||
68
pcireg/uefi/stat.c
Normal file
68
pcireg/uefi/stat.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
762
pcireg/uefi/stdio.c
Normal file
762
pcireg/uefi/stdio.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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];
|
||||
}
|
||||
330
pcireg/uefi/stdlib.c
Normal file
330
pcireg/uefi/stdlib.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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);
|
||||
}
|
||||
258
pcireg/uefi/string.c
Normal file
258
pcireg/uefi/string.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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((a<b && a+n>b) || (b<a && b+n>a)) {
|
||||
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; p<e; p++) if(*p==(uint8_t)c) return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
uint8_t *e, *p=(uint8_t*)s;
|
||||
if(s && n>0) {
|
||||
for(e=p+n; p<e; --e) if(*e==(uint8_t)c) return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *memmem(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;
|
||||
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 && src<e) {*dst++=*src++;} *dst=0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char_t *strcat(char_t *dst, const char_t *src)
|
||||
{
|
||||
if(src && dst) {
|
||||
dst += strlen(dst);
|
||||
while(*src) {*dst++=*src++;} *dst=0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int strcmp(const char_t *s1, const char_t *s2)
|
||||
{
|
||||
if(s1 && s2 && s1!=s2) {
|
||||
do{if(*s1!=*s2){return *s1-*s2;}s1++;s2++;}while(*s1!=0);
|
||||
return *s1-*s2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char_t *strncat(char_t *dst, const char_t *src, size_t n)
|
||||
{
|
||||
const char_t *e = src+n;
|
||||
if(src && dst && n>0) {
|
||||
dst += strlen(dst);
|
||||
while(*src && src<e) {*dst++=*src++;} *dst=0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
int strncmp(const char_t *s1, const char_t *s2, size_t n)
|
||||
{
|
||||
const char_t *e = s1+n;
|
||||
if(s1 && s2 && s1!=s2 && n>0) {
|
||||
do{if(*s1!=*s2){return *s1-*s2;}s1++;s2++;}while(*s1!=0 && s1<e);
|
||||
return *s1-*s2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char_t *strdup(const char_t *s)
|
||||
{
|
||||
int i = (strlen(s)+1) * sizeof(char_t);
|
||||
char_t *s2 = (char_t *)malloc(i);
|
||||
if(s2 != NULL) memcpy(s2, (void*)s, i);
|
||||
return s2;
|
||||
}
|
||||
|
||||
char_t *strchr(const char_t *s, int c)
|
||||
{
|
||||
if(s) {
|
||||
while(*s) {
|
||||
if(*s == (char_t)c) return (char_t*)s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_t *strrchr(const char_t *s, int c)
|
||||
{
|
||||
char_t *e;
|
||||
if(s) {
|
||||
e = (char_t*)s + strlen(s) - 1;
|
||||
while(s < e) {
|
||||
if(*e == (char_t)c) return e;
|
||||
s--;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_t *strstr(const char_t *haystack, const char_t *needle)
|
||||
{
|
||||
return memmem(haystack, strlen(haystack) * sizeof(char_t), needle, strlen(needle) * sizeof(char_t));
|
||||
}
|
||||
|
||||
char_t *_strtok_r(char_t *s, const char_t *d, char_t **p)
|
||||
{
|
||||
int c, sc;
|
||||
char_t *tok, *sp;
|
||||
|
||||
if(d == NULL || (s == NULL && (s=*p) == NULL)) return NULL;
|
||||
|
||||
c = *s++;
|
||||
for(sp = (char_t *)d; (sc=*sp++)!=0;) {
|
||||
if(c == sc) { *p=s; *(s-1)=0; return s-1; }
|
||||
}
|
||||
|
||||
if (c == 0) { *p=NULL; return NULL; }
|
||||
tok = s-1;
|
||||
while(1) {
|
||||
c = *s++;
|
||||
sp = (char_t *)d;
|
||||
do {
|
||||
if((sc=*sp++) == c) {
|
||||
if(c == 0) s = NULL;
|
||||
else *(s-1) = 0;
|
||||
*p = s;
|
||||
return tok;
|
||||
}
|
||||
} while(sc != 0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_t *strtok(char_t *s, const char_t *delim)
|
||||
{
|
||||
char_t *p = s;
|
||||
return _strtok_r (s, delim, &p);
|
||||
}
|
||||
|
||||
char_t *strtok_r(char_t *s, const char_t *delim, char_t **ptr)
|
||||
{
|
||||
return _strtok_r (s, delim, ptr);
|
||||
}
|
||||
|
||||
size_t strlen (const char_t *__s)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
if(!__s) return 0;
|
||||
for(ret = 0; __s[ret]; ret++);
|
||||
return ret;
|
||||
}
|
||||
145
pcireg/uefi/time.c
Normal file
145
pcireg/uefi/time.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* time.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 time.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <uefi.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
1420
pcireg/uefi/uefi.h
Normal file
1420
pcireg/uefi/uefi.h
Normal file
File diff suppressed because it is too large
Load Diff
55
pcireg/uefi/unistd.c
Normal file
55
pcireg/uefi/unistd.c
Normal file
@@ -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 <uefi.h>
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user