mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-12-28 05:55:27 +01:00
Add support for calling pcibios routines from the
bootloader. Implement the following routines: pcibios-device-count count the number of instances of a devid pcibios-read-config read pci config space pcibios-write-config write pci config space pcibios-find-devclass find the nth device with a given devclass pcibios-find-device find the nth device with a given devid pcibios-locator convert bus device function ti pcibios locator These commands are thin wrappers over their PCI BIOS 2.1 counterparts. More informaiton, such as it is, can be found in the standard. Export a nunmber of pcibios.X variables into the environment to report what the PCI IDENTIFY command returned. Also implmenet a new command line primitive (pci-device-count), but don't include it by default just yet, since it depends on the recently added words and any errors here can render a system unbootable. This is intended to allow the boot loader to do special things based on the hardware it finds. This could be have special settings that are optimized for the specific cards, or even loading special drivers. It goes without saying that writing to pci config space should not be done without a just cause and a sound mind. Sponsored by: Netflix
This commit is contained in:
parent
eec906cf32
commit
dd56e3b6bc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=271406
@ -727,6 +727,142 @@ static void fkey(FICL_VM *pVM)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
/*
|
||||
* pcibios-device-count (devid -- count)
|
||||
*
|
||||
* Returns the PCI BIOS' count of how many devices matching devid are in the system.
|
||||
* devid is the 32-bit vendor + device.
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosCountDevices(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t devid;
|
||||
int i;
|
||||
|
||||
devid = stackPopINT(pVM->pStack);
|
||||
|
||||
i = biospci_count_device_type(devid);
|
||||
|
||||
stackPushINT(pVM->pStack, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcibios-write-config (locator offset width value -- )
|
||||
*
|
||||
* Writes the specified config register.
|
||||
* Locator is bus << 8 | device << 3 | fuction
|
||||
* offset is the pci config register
|
||||
* width is 0 for byte, 1 for word, 2 for dword
|
||||
* value is the value to write
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosWriteConfig(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t value, width, offset, locator;
|
||||
|
||||
value = stackPopINT(pVM->pStack);
|
||||
width = stackPopINT(pVM->pStack);
|
||||
offset = stackPopINT(pVM->pStack);
|
||||
locator = stackPopINT(pVM->pStack);
|
||||
|
||||
biospci_write_config(locator, offset, width, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcibios-read-config (locator offset width -- value)
|
||||
*
|
||||
* Reads the specified config register.
|
||||
* Locator is bus << 8 | device << 3 | fuction
|
||||
* offset is the pci config register
|
||||
* width is 0 for byte, 1 for word, 2 for dword
|
||||
* value is the value to read from the register
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosReadConfig(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t value, width, offset, locator;
|
||||
|
||||
width = stackPopINT(pVM->pStack);
|
||||
offset = stackPopINT(pVM->pStack);
|
||||
locator = stackPopINT(pVM->pStack);
|
||||
|
||||
biospci_read_config(locator, offset, width, &value);
|
||||
|
||||
stackPushINT(pVM->pStack, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcibios-find-devclass (class index -- locator)
|
||||
*
|
||||
* Finds the index'th instance of class in the pci tree.
|
||||
* must be an exact match.
|
||||
* class is the class to search for.
|
||||
* index 0..N (set to 0, increment until error)
|
||||
*
|
||||
* Locator is bus << 8 | device << 3 | fuction (or -1 on error)
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosFindDevclass(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t index, class, locator;
|
||||
|
||||
index = stackPopINT(pVM->pStack);
|
||||
class = stackPopINT(pVM->pStack);
|
||||
|
||||
if (biospci_find_devclass(class, index, &locator))
|
||||
locator = 0xffffffff;
|
||||
|
||||
stackPushINT(pVM->pStack, locator);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcibios-find-device(devid index -- locator)
|
||||
*
|
||||
* Finds the index'th instance of devid in the pci tree.
|
||||
* must be an exact match.
|
||||
* class is the class to search for.
|
||||
* index 0..N (set to 0, increment until error)
|
||||
*
|
||||
* Locator is bus << 8 | device << 3 | fuction (or -1 on error)
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosFindDevice(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t index, devid, locator;
|
||||
|
||||
index = stackPopINT(pVM->pStack);
|
||||
devid = stackPopINT(pVM->pStack);
|
||||
|
||||
if (biospci_find_device(devid, index, &locator))
|
||||
locator = 0xffffffff;
|
||||
|
||||
stackPushINT(pVM->pStack, locator);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcibios-find-device(bus device function -- locator)
|
||||
*
|
||||
* converts bus, device, function to locator.
|
||||
*
|
||||
* Locator is bus << 8 | device << 3 | fuction
|
||||
*/
|
||||
static void
|
||||
ficlPciBiosLocator(FICL_VM *pVM)
|
||||
{
|
||||
uint32_t bus, device, function, locator;
|
||||
|
||||
function = stackPopINT(pVM->pStack);
|
||||
device = stackPopINT(pVM->pStack);
|
||||
bus = stackPopINT(pVM->pStack);
|
||||
|
||||
locator = biospci_locator(bus, device, function);
|
||||
|
||||
stackPushINT(pVM->pStack, locator);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Retrieves free space remaining on the dictionary
|
||||
*/
|
||||
@ -749,7 +885,6 @@ static void ficlDictIncrease(FICL_VM *pVM)
|
||||
stackPushPtr(pVM->pStack, &dictIncrease);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
f i c l C o m p i l e P l a t f o r m
|
||||
** Build FreeBSD platform extensions into the system dictionary
|
||||
@ -795,6 +930,14 @@ void ficlCompilePlatform(FICL_SYSTEM *pSys)
|
||||
dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __i386__
|
||||
dictAppendWord(dp, "pcibios-device-count", ficlPciBiosCountDevices, FW_DEFAULT);
|
||||
dictAppendWord(dp, "pcibios-read-config", ficlPciBiosReadConfig, FW_DEFAULT);
|
||||
dictAppendWord(dp, "pcibios-write-config", ficlPciBiosWriteConfig, FW_DEFAULT);
|
||||
dictAppendWord(dp, "pcibios-find-devclass", ficlPciBiosFindDevclass, FW_DEFAULT);
|
||||
dictAppendWord(dp, "pcibios-find-device", ficlPciBiosFindDevice, FW_DEFAULT);
|
||||
dictAppendWord(dp, "pcibios-locator", ficlPciBiosLocator, FW_DEFAULT);
|
||||
#endif
|
||||
|
||||
#if defined(PC98)
|
||||
ficlSetEnv(pSys, "arch-pc98", FICL_TRUE);
|
||||
@ -808,4 +951,3 @@ void ficlCompilePlatform(FICL_SYSTEM *pSys)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
47
sys/boot/forth/pcibios.4th
Normal file
47
sys/boot/forth/pcibios.4th
Normal file
@ -0,0 +1,47 @@
|
||||
\ Copyright (c) 2014 M. Warner Losh <imp@freebsd.org>
|
||||
\ 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.
|
||||
\
|
||||
\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
||||
\
|
||||
\ $FreeBSD$
|
||||
|
||||
only forth also support-functions also builtins definitions
|
||||
|
||||
\ pci-device-count pci-id
|
||||
\
|
||||
\ Counts the number of instances of pci-id in the system and reports
|
||||
\ it to the user.
|
||||
: pci-device-count
|
||||
0= if ( interpreted ) get_arguments then
|
||||
|
||||
0= if ." Need an argument" cr abort then
|
||||
\ First argument is 0 when we're interprated. See support.4th
|
||||
\ for get_arguments reading the rest of the line and parsing it
|
||||
\ stack: argN lenN ... arg1 len1 N
|
||||
hex ?number decimal
|
||||
0= if ." Bad pci-id given (must be legal hex value)" cr abort then
|
||||
dup pcibios-device-count ." Found " . ." instances of " hex . decimal cr
|
||||
;
|
||||
|
||||
also forth definitions also builtins
|
||||
|
||||
builtin: pci-device-count
|
@ -192,15 +192,69 @@ static struct pci_class
|
||||
static void biospci_enumerate(void);
|
||||
static void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi);
|
||||
|
||||
static int biospci_version;
|
||||
static int biospci_hwcap;
|
||||
|
||||
struct pnphandler biospcihandler =
|
||||
{
|
||||
"PCI BIOS",
|
||||
biospci_enumerate
|
||||
};
|
||||
|
||||
#define PCI_BIOS_PRESENT 0xb101
|
||||
#define FIND_PCI_DEVICE 0xb102
|
||||
#define FIND_PCI_CLASS_CODE 0xb103
|
||||
#define GENERATE_SPECIAL_CYCLE 0xb106
|
||||
#define READ_CONFIG_BYTE 0xb108
|
||||
#define READ_CONFIG_WORD 0xb109
|
||||
#define READ_CONFIG_DWORD 0xb10a
|
||||
#define WRITE_CONFIG_BYTE 0xb10b
|
||||
#define WRITE_CONFIG_WORD 0xb10c
|
||||
#define WRITE_CONFIG_DWORD 0xb10d
|
||||
#define GET_IRQ_ROUTING_OPTIONS 0xb10e
|
||||
#define SET_PCI_IRQ 0xb10f
|
||||
|
||||
#define PCI_INT 0x1a
|
||||
|
||||
#define PCI_SIGNATURE 0x20494350 /* AKA "PCI " */
|
||||
|
||||
void
|
||||
biospci_detect(void)
|
||||
{
|
||||
uint16_t version, hwcap, maxbus;
|
||||
char buf[24];
|
||||
|
||||
/* Find the PCI BIOS */
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = PCI_BIOS_PRESENT;
|
||||
v86.edi = 0x0;
|
||||
v86int();
|
||||
|
||||
/* Check for OK response */
|
||||
if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) ||
|
||||
(v86.edx != PCI_SIGNATURE))
|
||||
return;
|
||||
|
||||
version = v86.ebx & 0xffff;
|
||||
hwcap = v86.eax & 0xff;
|
||||
maxbus = v86.ecx & 0xff;
|
||||
#if 0
|
||||
printf("PCI BIOS %d.%d%s%s maxbus %d\n",
|
||||
bcd2bin((version >> 8) & 0xf), bcd2bin(version & 0xf),
|
||||
(hwcap & 1) ? " config1" : "", (hwcap & 2) ? " config2" : "",
|
||||
maxbus);
|
||||
#endif
|
||||
sprintf(buf, "%d", bcd2bin((version >> 8) & 0xf));
|
||||
setenv("pcibios.major", buf, 1);
|
||||
sprintf(buf, "%d", bcd2bin(version & 0xf));
|
||||
setenv("pcibios.minor", buf, 1);
|
||||
sprintf(buf, "%d", !!(hwcap & 1));
|
||||
setenv("pcibios.config1", buf, 1);
|
||||
sprintf(buf, "%d", !!(hwcap & 2));
|
||||
setenv("pcibios.config2", buf, 1);
|
||||
sprintf(buf, "%d", maxbus);
|
||||
setenv("pcibios.maxbus", buf, 1);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
biospci_enumerate(void)
|
||||
{
|
||||
@ -210,25 +264,6 @@ biospci_enumerate(void)
|
||||
struct pci_subclass *psc;
|
||||
struct pci_progif *ppi;
|
||||
|
||||
/* Find the PCI BIOS */
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = 0x1a;
|
||||
v86.eax = 0xb101;
|
||||
v86.edi = 0x0;
|
||||
v86int();
|
||||
|
||||
/* Check for OK response */
|
||||
if (V86_CY(v86.efl) || ((v86.eax & 0xff00) != 0) ||
|
||||
(v86.edx != 0x20494350))
|
||||
return;
|
||||
|
||||
biospci_version = v86.ebx & 0xffff;
|
||||
biospci_hwcap = v86.eax & 0xff;
|
||||
#if 0
|
||||
printf("PCI BIOS %d.%d%s%s\n",
|
||||
bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf),
|
||||
(biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : "");
|
||||
#endif
|
||||
/* Iterate over known classes */
|
||||
for (pc = pci_classes; pc->pc_class >= 0; pc++) {
|
||||
/* Iterate over subclasses */
|
||||
@ -289,8 +324,8 @@ int
|
||||
biospci_find_devclass(uint32_t class, int index, uint32_t *locator)
|
||||
{
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = 0x1a;
|
||||
v86.eax = 0xb103;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = FIND_PCI_CLASS_CODE;
|
||||
v86.ecx = class;
|
||||
v86.esi = index;
|
||||
v86int();
|
||||
@ -302,6 +337,25 @@ biospci_find_devclass(uint32_t class, int index, uint32_t *locator)
|
||||
*locator = v86.ebx;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
biospci_find_device(uint32_t devid, int index, uint32_t *locator)
|
||||
{
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = FIND_PCI_DEVICE;
|
||||
v86.edx = devid & 0xffff; /* EDX - Vendor ID */
|
||||
v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */
|
||||
v86.esi = index;
|
||||
v86int();
|
||||
|
||||
/* error */
|
||||
if (V86_CY(v86.efl) || (v86.eax & 0xff00))
|
||||
return (-1);
|
||||
|
||||
*locator = v86.ebx;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Configuration space access methods.
|
||||
* width = 0(byte), 1(word) or 2(dword).
|
||||
@ -310,8 +364,8 @@ int
|
||||
biospci_write_config(uint32_t locator, int offset, int width, uint32_t val)
|
||||
{
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = 0x1a;
|
||||
v86.eax = 0xb10b + width;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = WRITE_CONFIG_BYTE + width;
|
||||
v86.ebx = locator;
|
||||
v86.edi = offset;
|
||||
v86.ecx = val;
|
||||
@ -328,8 +382,8 @@ int
|
||||
biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val)
|
||||
{
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = 0x1a;
|
||||
v86.eax = 0xb108 + width;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = READ_CONFIG_BYTE + width;
|
||||
v86.ebx = locator;
|
||||
v86.edi = offset;
|
||||
v86int();
|
||||
@ -348,3 +402,27 @@ biospci_locator(int8_t bus, uint8_t device, uint8_t function)
|
||||
|
||||
return ((bus << 8) | ((device & 0x1f) << 3) | (function & 0x7));
|
||||
}
|
||||
|
||||
/*
|
||||
* Counts the number of instances of devid we have in the system, as least as
|
||||
* far as the PCI BIOS is able to tell.
|
||||
*/
|
||||
int
|
||||
biospci_count_device_type(uint32_t devid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; 1; i++) {
|
||||
v86.ctl = V86_FLAGS;
|
||||
v86.addr = PCI_INT;
|
||||
v86.eax = FIND_PCI_DEVICE;
|
||||
v86.edx = devid & 0xffff; /* EDX - Vendor ID */
|
||||
v86.ecx = (devid >> 16) & 0xffff; /* ECX - Device ID */
|
||||
v86.esi = i;
|
||||
v86int();
|
||||
if (V86_CY(v86.efl) || (v86.eax & 0xff00))
|
||||
break;
|
||||
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
@ -103,7 +103,10 @@ extern vm_offset_t memtop_copyin; /* memtop less heap size for the cases */
|
||||
extern uint32_t high_heap_size; /* extended memory region available */
|
||||
extern vm_offset_t high_heap_base; /* for use as the heap */
|
||||
|
||||
void biospci_detect(void);
|
||||
int biospci_count_device_type(uint32_t devid);
|
||||
int biospci_find_devclass(uint32_t class, int index, uint32_t *locator);
|
||||
int biospci_find_device(uint32_t devid, int index, uint32_t *locator);
|
||||
int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val);
|
||||
int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val);
|
||||
uint32_t biospci_locator(int8_t bus, uint8_t device, uint8_t function);
|
||||
|
@ -110,6 +110,7 @@ FILES+= loader.help loader.4th support.4th loader.conf
|
||||
FILES+= screen.4th frames.4th beastie.4th
|
||||
FILES+= brand.4th check-password.4th color.4th delay.4th
|
||||
FILES+= menu.4th menu-commands.4th menusets.4th shortcuts.4th version.4th
|
||||
FILES+= pcibios.4th
|
||||
FILESDIR_loader.conf= /boot/defaults
|
||||
|
||||
.if !exists(${DESTDIR}/boot/loader.rc)
|
||||
|
@ -183,6 +183,9 @@ main(void)
|
||||
/* detect SMBIOS for future reference */
|
||||
smbios_detect();
|
||||
|
||||
/* detect PCI BIOS for future reference */
|
||||
biospci_detect();
|
||||
|
||||
printf("\n");
|
||||
printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
|
||||
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
|
||||
|
Loading…
Reference in New Issue
Block a user