diff --git a/share/man/man9/bios.9 b/share/man/man9/bios.9 index b3a2ab64cab..e087f7bdc54 100644 --- a/share/man/man9/bios.9 +++ b/share/man/man9/bios.9 @@ -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 diff --git a/sys/amd64/amd64/bios.c b/sys/amd64/amd64/bios.c index d08f5ccd160..c8985c1f773 100644 --- a/sys/amd64/amd64/bios.c +++ b/sys/amd64/amd64/bios.c @@ -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); -} diff --git a/sys/amd64/include/pc/bios.h b/sys/amd64/include/pc/bios.h index 87279727afe..ffad3695f75 100644 --- a/sys/amd64/include/pc/bios.h +++ b/sys/amd64/include/pc/bios.h @@ -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_ */ diff --git a/sys/i386/i386/bios.c b/sys/i386/i386/bios.c index 332bd6c4dcc..9d5df7de160 100644 --- a/sys/i386/i386/bios.c +++ b/sys/i386/i386/bios.c @@ -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+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) 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 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 diff --git a/sys/i386/i386/elan-mmcr.c b/sys/i386/i386/elan-mmcr.c index 8e1ffb13225..66c218f2ee4 100644 --- a/sys/i386/i386/elan-mmcr.c +++ b/sys/i386/i386/elan-mmcr.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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"); diff --git a/sys/i386/i386/geode.c b/sys/i386/i386/geode.c index 2702f21eb25..a32d68cdd19 100644 --- a/sys/i386/i386/geode.c +++ b/sys/i386/i386/geode.c @@ -39,6 +39,34 @@ __FBSDID("$FreeBSD$"); #include #include +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); } diff --git a/sys/i386/include/pc/bios.h b/sys/i386/include/pc/bios.h index c7362a96408..4533de75acd 100644 --- a/sys/i386/include/pc/bios.h +++ b/sys/i386/include/pc/bios.h @@ -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_ */