From: | "Thomas E. Spanjaard" <tgen@xxxxxxxxxxxxx> |
Date: | Fri, 12 Jan 2007 19:00:13 +0000 |
Cheers, -- Thomas E. Spanjaard tgen@netphreax.net
diff -r c63dd4a6b22d sys/conf/options --- a/sys/conf/options Wed Jan 10 06:01:06 2007 +0000 +++ b/sys/conf/options Fri Jan 12 13:23:27 2007 +0000 @@ -77,6 +77,7 @@ TWA_FLASH_FIRMWARE opt_twa.h #options for ACPI support ACPI_DEBUG opt_acpi.h ACPI_NO_SEMAPHORES opt_acpi.h +ACPI_QUIRK_VMWARE opt_acpi.h # Miscellaneous options. COMPAT_DF12 opt_compatdf12.h diff -r c63dd4a6b22d sys/dev/acpica5/acpi.c --- a/sys/dev/acpica5/acpi.c Wed Jan 10 06:01:06 2007 +0000 +++ b/sys/dev/acpica5/acpi.c Sat Jan 20 05:52:40 2007 +0000 @@ -31,6 +31,7 @@ */ #include "opt_acpi.h" + #include <sys/param.h> #include <sys/kernel.h> #include <sys/proc.h> @@ -81,6 +82,11 @@ struct mtx acpi_mutex; struct mtx acpi_mutex; #endif +/* + * XXX TGEN We should allow for quirks to be, optionally, more specific + * regarding hardware they match, e.g. specifying CreatorId and + * CreatorRevision. + */ struct acpi_quirks { char *OemId; uint32_t OemRevision; @@ -94,7 +100,18 @@ static struct acpi_quirks acpi_quirks_ta /* Bad PCI routing table. Used on some SuperMicro boards. */ { "PTLTD ", 0x06040000, "pci_link" }, #endif - +#ifdef ACPI_QUIRK_VMWARE + /* + * VMware's ACPI-fast24 timer runs roughly 65 times too fast, and not + * predictably / monotonic either. This is observed at least under SMP + * conditions. + * + * NOTE: this combination of OemId and OemRevision is NOT unique; it's also + * known and/or suspected that at least some SuperMicro boards and the + * Compaq Presario 1952 use this combination. + */ + { "PTLTD ", 0x06040000, "timer" }, +#endif /* ACPI_QUIRK_VMWARE */ { NULL, 0, NULL } }; @@ -652,7 +669,7 @@ acpi_quirks_set(void) /* XXX No strcasecmp but this is good enough. */ if (*env == 'Y' || *env == 'y') goto out; - freeenv(env); + kfreeenv(env); } if ((env = kgetenv("debug.acpi.disabled")) != NULL) { if (strstr("quirks", env) != NULL) @@ -673,9 +690,7 @@ acpi_quirks_set(void) if ((tmp = kmalloc(len, M_TEMP, M_NOWAIT)) == NULL) goto out; ksprintf(tmp, "%s %s", env ? env : "", quirk->value); -#ifdef notyet - setenv("debug.acpi.disabled", tmp); -#endif /* notyet */ + ksetenv("debug.acpi.disabled", tmp); kfree(tmp, M_TEMP); break; } @@ -683,7 +698,7 @@ acpi_quirks_set(void) out: if (env) - freeenv(env); + kfreeenv(env); } /* diff -r c63dd4a6b22d sys/dev/acpica5/acpi_timer.c --- a/sys/dev/acpica5/acpi_timer.c Wed Jan 10 06:01:06 2007 +0000 +++ b/sys/dev/acpica5/acpi_timer.c Fri Jan 12 13:21:16 2007 +0000 @@ -27,7 +27,9 @@ * $FreeBSD: src/sys/dev/acpica/acpi_timer.c,v 1.33 2004/05/30 20:08:23 phk Exp $ * $DragonFly: src/sys/dev/acpica5/acpi_timer.c,v 1.11 2006/12/22 23:26:14 swildner Exp $ */ + #include "opt_acpi.h" + #include <sys/param.h> #include <sys/bus.h> #include <sys/kernel.h> diff -r c63dd4a6b22d sys/kern/kern_environment.c --- a/sys/kern/kern_environment.c Wed Jan 10 06:01:06 2007 +0000 +++ b/sys/kern/kern_environment.c Mon Jan 22 08:03:13 2007 +0000 @@ -29,23 +29,91 @@ /* * The unified bootloader passes us a pointer to a preserved copy of - * bootstrap/kernel environment variables. + * bootstrap/kernel environment variables. We convert them to a dynamic array + * of strings later when the VM subsystem is up. * We make these available using sysctl for both in-kernel and - * out-of-kernel consumers. + * out-of-kernel consumers, as well as the k{get,set,unset,test,free}env() + * functions for in-kernel consumers. * * Note that the current sysctl infrastructure doesn't allow * dynamic insertion or traversal through handled spaces. Grr. + * + * Note also that the dynamic kernel environment space is not yet exported via + * sysctl. It should be handled somewhat like kinfo. */ #include <sys/param.h> #include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/malloc.h> +#include <sys/spinlock.h> +#include <sys/spinlock2.h> #include <sys/systm.h> #include <sys/sysctl.h> -#include <sys/libkern.h> - -char *kern_envp; - -static char *kernenv_next(char *cp); + +/* exported variables */ +char *kern_envp; /* sys/systm.h */ + +/* local variables */ +char **kenv_dynp; +int kenv_isdynamic; +struct spinlock kenv_dynlock; + +/* constants */ +MALLOC_DEFINE(M_KENV, "kenv", "kernel environment dynamic storage"); +#define KENV_DYNMAXNUM 512 +#define KENV_MAXNAMELEN 128 +#define KENV_MAXVALLEN 128 + +/* local prototypes */ +static char *kenv_getstring_dynamic(const char *, int *); +static char *kenv_getstring_static(const char*); +static char *kernenv_next(char *); + +/* + * Look up a string in the dynamic environment array. + * + * Must be called with kenv_dynlock held. + */ +static char * +kenv_getstring_dynamic(const char *name, int *idx) +{ + char *cp; + int len, i; + + len = strlen(name); + /* note: kunsetenv() never leaves gaps in the array */ + for (cp = kenv_dynp[0], i = 0; cp != NULL; cp = kenv_dynp[i++]) { + if ((strncmp(cp, name, len) == 0) && (cp[len] == '=')) { + if (idx != NULL) + *idx = i; + return(cp + len + 1); + } + } + return(NULL); +} + +/* + * Look up a string in the static environment array. + */ +static char * +kenv_getstring_static(const char *name) +{ + char *cp, *ep; + int len; + + for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { + for (ep = cp; (*ep != '=') && (*ep != 0); ep++) + ; + if (*ep != '=') + continue; + len = ep - cp; + ep++; + if (!strncmp(name, cp, len) && name[len] == 0) + return(ep); + } + return(NULL); +} /* * Look up an environment variable by name. @@ -53,20 +121,132 @@ char * char * kgetenv(const char *name) { - char *cp, *ep; - int len; - - for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { - for (ep = cp; (*ep != '=') && (*ep != 0); ep++) - ; - if (*ep != '=') - continue; - len = ep - cp; - ep++; - if (!strncmp(name, cp, len) && name[len] == 0) - return(ep); - } - return(NULL); + char buf[KENV_MAXNAMELEN + 1 + KENV_MAXVALLEN + 1]; + char *ret, *cp; + int len; + + if (kenv_isdynamic) { + spin_lock_wr(&kenv_dynlock); + cp = kenv_getstring_dynamic(name, NULL); + if (cp != NULL) { + strcpy(buf, cp); + spin_unlock_wr(&kenv_dynlock); + len = strlen(buf) + 1; + ret = kmalloc(len, M_KENV, M_WAITOK); + strcpy(ret, buf); + } else { + spin_unlock_wr(&kenv_dynlock); + ret = NULL; + } + } else + ret = kenv_getstring_static(name); + return(ret); +} + +/* + * Set an environment variable by name. + */ +int +ksetenv(const char *name, const char *value) +{ + char *buf, *cp, *oldenv; + int namelen, vallen, i; + + if (kenv_isdynamic) { + namelen = strlen(name) + 1; + vallen = strlen(value) + 1; + if ((namelen > KENV_MAXNAMELEN) || (vallen > KENV_MAXVALLEN)) + return(-1); + buf = kmalloc(namelen + vallen, M_KENV, M_WAITOK); + ksprintf(buf, "%s=%s", name, value); + + spin_lock_wr(&kenv_dynlock); + cp = kenv_getstring_dynamic(name, &i); + if (cp != NULL) { + /* replace existing environment variable */ + oldenv = kenv_dynp[i]; + kenv_dynp[i] = buf; + spin_unlock_wr(&kenv_dynlock); + kfree(oldenv, M_KENV); + } else { + /* new environment variable: find first free slot */ + for (i = 0; (cp = kenv_dynp[i]) != NULL; i++) + ; + + /* bounds checking */ + if (i < 0 || i >= (KENV_DYNMAXNUM - 1)) { + kfree(buf, M_KENV); + spin_unlock_wr(&kenv_dynlock); + return(-1); + } + + kenv_dynp[i] = buf; + kenv_dynp[i + 1] = NULL; + spin_unlock_wr(&kenv_dynlock); + } + return(0); + } else { + kprintf("WARNING: ksetenv: dynamic array not created yet\n"); + return(-1); + } +} + +/* + * Unset an environment variable by name. + */ +int +kunsetenv(const char *name) +{ + char *cp, *oldenv; + int i, j; + + if (kenv_isdynamic) { + spin_lock_wr(&kenv_dynlock); + cp = kenv_getstring_dynamic(name, &i); + if (cp != NULL) { + oldenv = kenv_dynp[i]; + for (j = i + 1; kenv_dynp[j] != NULL; j++) + kenv_dynp[i++] = kenv_dynp[j]; + kenv_dynp[i] = NULL; + spin_unlock_wr(&kenv_dynlock); + kfree(oldenv, M_KENV); + return(0); + } + spin_unlock_wr(&kenv_dynlock); + return(-1); + } else { + kprintf("WARNING: kunsetenv: dynamic array not created yet\n"); + return(-1); + } +} + +/* + * Free an environment variable that has been copied for a consumer. + */ +void +kfreeenv(char *env) +{ + if (kenv_isdynamic) + kfree(env, M_KENV); +} + +/* + * Test if an environment variable is defined. + */ +int +ktestenv(const char *name) +{ + char *cp; + + if (kenv_isdynamic) { + spin_lock_wr(&kenv_dynlock); + cp = kenv_getstring_dynamic(name, NULL); + spin_unlock_wr(&kenv_dynlock); + } else + cp = kenv_getstring_static(name); + if (cp != NULL) + return(1); + return(0); } /* @@ -81,6 +261,7 @@ kgetenv_string(const char *name, char *d if (tmp != NULL) { strncpy(data, tmp, size); data[size - 1] = 0; + kfreeenv(tmp); return (1); } else return (0); @@ -116,15 +297,21 @@ kgetenv_quad(const char *name, quad_t *d return(0); iv = strtoq(value, &vtp, 0); - if ((vtp == value) || (*vtp != '\0')) + if ((vtp == value) || (*vtp != '\0')) { + kfreeenv(value); return(0); + } *data = iv; + kfreeenv(value); return(1); } +/* + * Boottime kernel environment sysctl handler. + */ static int -sysctl_kernenv(SYSCTL_HANDLER_ARGS) +sysctl_kenv_boot(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; @@ -153,8 +340,46 @@ sysctl_kernenv(SYSCTL_HANDLER_ARGS) error = SYSCTL_OUT(req, cp, strlen(cp) + 1); return (error); } - -SYSCTL_NODE(_kern, OID_AUTO, environment, CTLFLAG_RD, sysctl_kernenv, "kernel environment space"); +SYSCTL_NODE(_kern, OID_AUTO, environment, CTLFLAG_RD, sysctl_kenv_boot, + "kernel boot environment space"); + +#ifdef notyet +/* + * Runtime kernel environment sysctl handler. + */ +static int +sysctl_kenv(SYSCTL_HANDLER_ARGS) +{ + int *name = (int *)arg1; + u_int namelen = arg2; + char *bufp; + ptr_t buf; + int total, i, len; + + if (kenv_isdynamic) { + spin_lock_wr(&kenv_dynlock); + if (oidp->oid_number == KERN_ENV_ALL) { + total = 0; + for (i = 0; kenv_dynp[i] != NULL; i++) { + len = strlen(kenv_dynp[i]) + 1; + total += len; + } + bufp = kmalloc(total, M_KENV, M_WAITOK); + buf = bufp + for (i = 0; kenv_dynp[i] != NULL; i++) { + len = strlen(kenv_dynp[i]) + 1; + strcpy(buf, kenv_dynp[i]); + buf += len; + } + error = SYSCTL_OUT(req, bufp, total); + return(error); + } + } + return(-1); +} +SYSCTL_NODE(_kern, OID_AUTO, env, CTLFLAG_RD, sysctl_kenv, + "kernel runtime environment space"); +#endif /* notyet */ /* * Find the next entry after the one which (cp) falls within, return a @@ -197,3 +422,54 @@ tunable_str_init(void *data) TUNABLE_STR_FETCH(d->path, d->var, d->size); } +/* + * Create the dynamic kenv stuff, and copy in the static kenv as passed by the + * bootloader. + */ +static void +kenv_init(void *dummy) +{ + char *cp; + int len, i; + + kenv_dynp = kmalloc(KENV_DYNMAXNUM * sizeof(char *), M_KENV, + M_WAITOK | M_ZERO); + + /* copy the static kenv to our dynamic kenv */ + i = 0; + for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) { + len = strlen(cp) + 1; + if (i < (KENV_DYNMAXNUM - 1)) { + kenv_dynp[i] = kmalloc(len, M_KENV, M_WAITOK); + strcpy(kenv_dynp[i++], cp); + } else + kprintf("WARNING: kenv: exhausted dynamic storage, " + "ignoring string %s\n", cp); + } + kenv_dynp[i] = NULL; + + spin_init(&kenv_dynlock); + kenv_isdynamic = 1; +} +SYSINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, kenv_init, NULL); + +/* + * Destroy the dynamic kenv stuff. + */ +static void +kenv_uninit(void *dummy) +{ + int i; + + if (kenv_isdynamic) { + spin_lock_wr(&kenv_dynlock); + /* destroy our environment variables */ + for (i = 0; kenv_dynp[i] != NULL; i++) + kfree(kenv_dynp[i], M_KENV); + kenv_isdynamic = 0; + kfree(kenv_dynp, M_KENV); + spin_unlock_wr(&kenv_dynlock); + spin_uninit(&kenv_dynlock); + } +} +SYSUNINIT(kenv, SI_SUB_KMEM, SI_ORDER_ANY, kenv_uninit, NULL); diff -r c63dd4a6b22d sys/sys/systm.h --- a/sys/sys/systm.h Wed Jan 10 06:01:06 2007 +0000 +++ b/sys/sys/systm.h Sat Jan 20 04:23:52 2007 +0000 @@ -223,9 +223,19 @@ void cons_lock(void); void cons_lock(void); void cons_unlock(void); +/* + * Kernel environment support functions and sundry. + * + * XXX TGEN Fix all calls to freeenv() and testenv() to their k- counterparts, + * so that these compat defines can go the way of the bit bucket. + */ char *kgetenv (const char *name); -#define testenv kgetenv -#define freeenv(p) +int ksetenv (const char *name, const char *value); +int kunsetenv (const char *name); +void kfreeenv(char *env); +#define freeenv kfreeenv +int ktestenv(const char *name); +#define testenv ktestenv int kgetenv_int (const char *name, int *data); int kgetenv_string (const char *name, char *data, int size); int kgetenv_quad (const char *name, quad_t *data);
Attachment:
signature.asc
Description: OpenPGP digital signature