mirror of
https://git.FreeBSD.org/src.git
synced 2025-02-09 02:26:27 +00:00
Make the facility for recognizing BIOS-signatures more general
and return a printable representation. This fixes recognition of the PC Engines WRAP and improves the recognition of the Soekris boards (Bios version can now be seen in the dmesg output for instance). Also, add watchdog support for PCM-582x platforms. Submitted by: Adrian Steinmann <ast@marabu.ch> Slightly changed by: phk PR: 81360
This commit is contained in:
parent
514bcb8955
commit
636d90fc5c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=148231
@ -30,7 +30,8 @@
|
||||
.Sh NAME
|
||||
.Nm bios_sigsearch ,
|
||||
.Nm bios32_SDlookup ,
|
||||
.Nm bios32
|
||||
.Nm bios32 ,
|
||||
.Nm bios_oem_strings
|
||||
.Nd interact with PC BIOS
|
||||
.Sh SYNOPSIS
|
||||
.In sys/param.h
|
||||
@ -50,6 +51,23 @@
|
||||
.Vt extern struct bios32_SDentry PCIbios ;
|
||||
.Vt extern struct SMBIOS_table SMBIOStable ;
|
||||
.Vt extern struct DMI_table DMItable ;
|
||||
.Ft int
|
||||
.Fn bios_oem_strings "struct bios_oem *oem" "u_char *buffer" "size_t maxlen"
|
||||
.Bd -literal
|
||||
struct bios_oem_signature {
|
||||
char * anchor; /* search anchor string in BIOS memory */
|
||||
size_t offset; /* offset from anchor (may be negative) */
|
||||
size_t totlen; /* total length of BIOS string to copy */
|
||||
};
|
||||
struct bios_oem_range {
|
||||
u_int from; /* shouldn't be below 0xe0000 */
|
||||
u_int to; /* shouldn't be above 0xfffff */
|
||||
};
|
||||
struct bios_oem {
|
||||
struct bios_oem_range range;
|
||||
struct bios_oem_signature signature[];
|
||||
};
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
These functions provide a general-purpose interface for dealing with
|
||||
the BIOS functions and data encountered on x86 PC-architecture systems.
|
||||
@ -75,6 +93,36 @@ bytes and the search repeated.
|
||||
If the signature is found, its effective
|
||||
physical address is returned.
|
||||
If no signature is found, zero is returned.
|
||||
.It Fn bios_oem_strings
|
||||
Searches a given BIOS memory range for one or more strings,
|
||||
and composes a printable concatenation of those found.
|
||||
The routine expects a structure describing the BIOS address
|
||||
.Fa range
|
||||
(within 0xe0000 - 0xfffff), and a { NULL, 0, 0 } -terminated array of
|
||||
.Fa bios_oem_signature
|
||||
structures which define the
|
||||
.Fa anchor
|
||||
string, an
|
||||
.Fa offset
|
||||
from the beginning of the match (which may be negative), and
|
||||
.Fa totlen
|
||||
number of bytes to be collected from BIOS memory starting at that offset.
|
||||
Unmatched anchors are ignored, whereas matches are copied from BIOS memory
|
||||
starting at their corresponding
|
||||
.Fa offset
|
||||
with unprintable characters being replaced with space, and consecutive spaces
|
||||
being suppressed. This composed string is stored in
|
||||
.Fa buffer
|
||||
up to the given
|
||||
.Fa maxlen
|
||||
bytes (including trailing '\\0', and any trailing space surpressed).
|
||||
If an error is encountered, i.e. trying to read out of said BIOS range,
|
||||
other invalid input, or
|
||||
.Fa buffer
|
||||
overflow, a negative integer is returned, otherwise the
|
||||
length of the composed string is returned. In particular, a return
|
||||
value of 0 means that none of the given anchor strings were found in
|
||||
the specified BIOS memory range.
|
||||
.It Fn BIOS_VADDRTOPADDR
|
||||
Returns the effective physical address which corresponds to the kernel
|
||||
virtual address
|
||||
|
@ -93,18 +93,3 @@ bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
const u_char *
|
||||
bios_string(u_int from, u_int to, const u_char *string, int len)
|
||||
{
|
||||
const char *t, *te;
|
||||
|
||||
if (len == 0)
|
||||
len = strlen(string);
|
||||
t = (const char *)(KERNBASE + from);
|
||||
te = (const char *)(KERNBASE + to);
|
||||
for (; t <= te; t++)
|
||||
if (!memcmp(string, t, len))
|
||||
return (t);
|
||||
return (NULL);
|
||||
}
|
||||
|
@ -48,7 +48,22 @@ struct bios_smap {
|
||||
u_int32_t type;
|
||||
} __packed;
|
||||
|
||||
const u_char *bios_string(u_int from, u_int to, const u_char *string, int len);
|
||||
struct bios_oem_signature {
|
||||
char * anchor; /* search anchor string in BIOS memory */
|
||||
size_t offset; /* offset from anchor (may be negative) */
|
||||
size_t totlen; /* total length of BIOS string to copy */
|
||||
} __packed;
|
||||
struct bios_oem_range {
|
||||
u_int from; /* shouldn't be below 0xe0000 */
|
||||
u_int to; /* shouldn't be above 0xfffff */
|
||||
} __packed;
|
||||
struct bios_oem {
|
||||
struct bios_oem_range range;
|
||||
struct bios_oem_signature signature[];
|
||||
} __packed;
|
||||
|
||||
extern int
|
||||
bios_oem_strings(struct bios_oem *oem, u_char *buffer, size_t maxlen);
|
||||
|
||||
|
||||
#endif /* _MACHINE_PC_BIOS_H_ */
|
||||
|
@ -475,19 +475,81 @@ bios16(struct bios_args *args, char *fmt, ...)
|
||||
return (i);
|
||||
}
|
||||
|
||||
const u_char *
|
||||
bios_string(u_int from, u_int to, const u_char *string, int len)
|
||||
int bios_oem_strings(struct bios_oem *oem, u_char *buffer, size_t maxlen)
|
||||
{
|
||||
const char *t, *te;
|
||||
size_t idx = 0;
|
||||
struct bios_oem_signature *sig;
|
||||
u_int from, to;
|
||||
u_char c, *s, *se, *str, *bios_str;
|
||||
size_t i, off, len, tot;
|
||||
|
||||
if (len == 0)
|
||||
len = strlen(string);
|
||||
t = (const char *)(KERNBASE + from);
|
||||
te = (const char *)(KERNBASE + to);
|
||||
for (; t <= te; t++)
|
||||
if (!memcmp(string, t, len))
|
||||
return (t);
|
||||
return (NULL);
|
||||
if ( !oem || !buffer || maxlen<2 )
|
||||
return(-1);
|
||||
|
||||
sig = oem->signature;
|
||||
if (!sig)
|
||||
return(-2);
|
||||
|
||||
from = oem->range.from;
|
||||
to = oem->range.to;
|
||||
if ( (to<=from) || (from<BIOS_START) || (to>(BIOS_START+BIOS_SIZE)) )
|
||||
return(-3);
|
||||
|
||||
while (sig->anchor != NULL) {
|
||||
str = sig->anchor;
|
||||
len = strlen(str);
|
||||
off = sig->offset;
|
||||
tot = sig->totlen;
|
||||
/* make sure offset doesn't go beyond bios area */
|
||||
if ( (to+off)>(BIOS_START+BIOS_SIZE) ||
|
||||
((from+off)<BIOS_START) ) {
|
||||
printf("sys/i386/i386/bios.c: sig '%s' "
|
||||
"from 0x%0x to 0x%0x offset %d "
|
||||
"out of BIOS bounds 0x%0x - 0x%0x\n",
|
||||
str, from, to, off,
|
||||
BIOS_START, BIOS_START+BIOS_SIZE);
|
||||
return(-4);
|
||||
}
|
||||
/* make sure we don't overrun return buffer */
|
||||
if (idx + tot > maxlen - 1) {
|
||||
printf("sys/i386/i386/bios.c: sig '%s' "
|
||||
"idx %d + tot %d = %d > maxlen-1 %d\n",
|
||||
str, idx, tot, idx+tot, maxlen-1);
|
||||
return(-5);
|
||||
}
|
||||
bios_str = NULL;
|
||||
s = (u_char *)BIOS_PADDRTOVADDR(from);
|
||||
se = (u_char *)BIOS_PADDRTOVADDR(to-len);
|
||||
for (; s<se; s++) {
|
||||
if (!memcmp(str, s, len)) {
|
||||
bios_str = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* store pretty version of totlen bytes of bios string with
|
||||
* given offset; 0x20 - 0x7E are printable; uniquify spaces
|
||||
*/
|
||||
if (bios_str) {
|
||||
for (i=0; i<tot; i++) {
|
||||
c = bios_str[i+off];
|
||||
if ( (c < 0x20) || (c > 0x7E) )
|
||||
c = ' ';
|
||||
if (idx == 0) {
|
||||
if (c != ' ')
|
||||
buffer[idx++] = c;
|
||||
} else if ( (c != ' ') ||
|
||||
((c == ' ') && (buffer[idx-1] != ' ')) )
|
||||
buffer[idx++] = c;
|
||||
}
|
||||
}
|
||||
sig++;
|
||||
}
|
||||
/* remove a final trailing space */
|
||||
if ( (idx > 1) && (buffer[idx-1] == ' ') )
|
||||
idx--;
|
||||
buffer[idx] = '\0';
|
||||
return (idx);
|
||||
}
|
||||
|
||||
#ifdef DEV_ISA
|
||||
|
@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/led/led.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/elan_mmcr.h>
|
||||
#include <machine/pc/bios.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
@ -77,6 +78,20 @@ static u_int pps_a, pps_d;
|
||||
static u_int echo_a, echo_d;
|
||||
#endif /* CPU_ELAN_PPS */
|
||||
|
||||
#ifdef CPU_SOEKRIS
|
||||
|
||||
static struct bios_oem bios_soekris = {
|
||||
{ 0xf0000, 0xf1000 },
|
||||
{
|
||||
{ "Soekris", 0, 8 }, /* Soekris Engineering. */
|
||||
{ "net4", 0, 8 }, /* net45xx */
|
||||
{ "comBIOS", 0, 54 }, /* comBIOS ver. 1.26a 20040819 ... */
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static u_int led_cookie[32];
|
||||
static struct cdev *led_dev[32];
|
||||
|
||||
@ -449,6 +464,11 @@ static void
|
||||
elan_drvinit(void)
|
||||
{
|
||||
|
||||
#ifdef CPU_SOEKRIS
|
||||
#define BIOS_OEM_MAXLEN 72
|
||||
static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
|
||||
#endif /* CPU_SOEKRIS */
|
||||
|
||||
/* If no elan found, just return */
|
||||
if (mmcrptr == NULL)
|
||||
return;
|
||||
@ -466,6 +486,9 @@ elan_drvinit(void)
|
||||
UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
|
||||
|
||||
#ifdef CPU_SOEKRIS
|
||||
if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
|
||||
printf("Elan-mmcr %s\n", bios_oem);
|
||||
|
||||
/* Create the error LED on GPIO9 */
|
||||
led_cookie[9] = 0x02000c34;
|
||||
led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
|
||||
|
@ -39,6 +39,34 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/led/led.h>
|
||||
#include <machine/pc/bios.h>
|
||||
|
||||
static struct bios_oem bios_soekris = {
|
||||
{ 0xf0000, 0xf1000 },
|
||||
{
|
||||
{ "Soekris", 0, 8 }, /* Soekris Engineering. */
|
||||
{ "net4", 0, 8 }, /* net45xx */
|
||||
{ "comBIOS", 0, 54 }, /* comBIOS ver. 1.26a 20040819 ... */
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
static struct bios_oem bios_pcengines = {
|
||||
{ 0xf9000, 0xfa000 },
|
||||
{
|
||||
{ "PC Engines WRAP", 0, 28 }, /* PC Engines WRAP.1C v1.03 */
|
||||
{ "tinyBIOS", 0, 28 }, /* tinyBIOS V1.4a (C)1997-2003 */
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
static struct bios_oem bios_advantech = {
|
||||
{ 0xfe000, 0xff000 },
|
||||
{
|
||||
{ "**** PCM-582", 5, 33 }, /* PCM-5823 BIOS V1.12 ... */
|
||||
{ "GXm-Cx5530", -11, 35 }, /* 06/07/2002-GXm-Cx5530... */
|
||||
{ NULL, 0, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned cba;
|
||||
static unsigned gpio;
|
||||
static unsigned geode_counter;
|
||||
@ -115,9 +143,23 @@ geode_watchdog(void *foo __unused, u_int cmd, int *error)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The Advantech PCM-582x watchdog expects 0x1 at I/O port 0x0443
|
||||
* every 1.6 secs +/- 30%. Writing 0x0 disables the watchdog
|
||||
* NB: reading the I/O port enables the timer as well
|
||||
*/
|
||||
static void
|
||||
advantech_watchdog(void *foo __unused, u_int cmd, int *error)
|
||||
{
|
||||
outb(0x0443, (cmd & WD_INTERVAL) ? 1 : 0);
|
||||
*error = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
geode_probe(device_t self)
|
||||
{
|
||||
#define BIOS_OEM_MAXLEN 80
|
||||
static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
|
||||
|
||||
if (pci_get_devid(self) == 0x0515100b) {
|
||||
if (geode_counter == 0) {
|
||||
@ -139,14 +181,12 @@ geode_probe(device_t self)
|
||||
gpio = pci_read_config(self, PCIR_BAR(0), 4);
|
||||
gpio &= ~0x1f;
|
||||
printf("Geode GPIO@ = %x\n", gpio);
|
||||
if (NULL !=
|
||||
bios_string(0xf0000, 0xf0100, "Soekris Engineering", 0)) {
|
||||
printf("Soekris Engineering NET4801 platform\n");
|
||||
if ( bios_oem_strings(&bios_soekris,
|
||||
bios_oem, BIOS_OEM_MAXLEN) > 0 ) {
|
||||
led1b = 20;
|
||||
led1 = led_create(led_func, &led1b, "error");
|
||||
} else if (NULL !=
|
||||
bios_string(0xf9000, 0xf9000, "PC Engines WRAP.1C ", 0)) {
|
||||
printf("PC Engines WRAP.1C platfrom\n");
|
||||
} else if ( bios_oem_strings(&bios_pcengines,
|
||||
bios_oem, BIOS_OEM_MAXLEN) > 0 ) {
|
||||
led1b = -2;
|
||||
led2b = -3;
|
||||
led3b = -18;
|
||||
@ -154,11 +194,20 @@ geode_probe(device_t self)
|
||||
led2 = led_create(led_func, &led2b, "led2");
|
||||
led3 = led_create(led_func, &led3b, "led3");
|
||||
/*
|
||||
* Turn on first LED so we don't make people think
|
||||
* their box just died.
|
||||
*/
|
||||
* Turn on first LED so we don't make
|
||||
* people think their box just died.
|
||||
*/
|
||||
led_func(&led1b, 1);
|
||||
}
|
||||
if ( strlen(bios_oem) )
|
||||
printf("Geode %s\n", bios_oem);
|
||||
} else if (pci_get_devid(self) == 0x01011078) {
|
||||
if ( bios_oem_strings(&bios_advantech,
|
||||
bios_oem, BIOS_OEM_MAXLEN) > 0 ) {
|
||||
printf("Geode %s\n", bios_oem);
|
||||
EVENTHANDLER_REGISTER(watchdog_list, advantech_watchdog,
|
||||
NULL, 0);
|
||||
}
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
@ -281,7 +281,22 @@ struct bios_smap {
|
||||
u_int32_t type;
|
||||
} __packed;
|
||||
|
||||
const u_char *bios_string(u_int from, u_int to, const u_char *string, int len);
|
||||
struct bios_oem_signature {
|
||||
char * anchor; /* search anchor string in BIOS memory */
|
||||
size_t offset; /* offset from anchor (may be negative) */
|
||||
size_t totlen; /* total length of BIOS string to copy */
|
||||
} __packed;
|
||||
struct bios_oem_range {
|
||||
u_int from; /* shouldn't be below 0xe0000 */
|
||||
u_int to; /* shouldn't be above 0xfffff */
|
||||
} __packed;
|
||||
struct bios_oem {
|
||||
struct bios_oem_range range;
|
||||
struct bios_oem_signature signature[];
|
||||
} __packed;
|
||||
|
||||
extern int
|
||||
bios_oem_strings(struct bios_oem *oem, u_char *buffer, size_t maxlen);
|
||||
|
||||
|
||||
#endif /* _MACHINE_PC_BIOS_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user