1
0
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:
Poul-Henning Kamp 2005-07-21 09:48:37 +00:00
parent 514bcb8955
commit 636d90fc5c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=148231
7 changed files with 235 additions and 38 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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

View File

@ -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");

View File

@ -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);
}

View File

@ -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_ */