summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf_obj.c
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2009-06-23 22:42:39 +0000
committerjeff <jeff@FreeBSD.org>2009-06-23 22:42:39 +0000
commit5bc3a65e406b90cd9e2a47b79117e453bdb56413 (patch)
tree5644c551dea0298e335cc77383345323c6eb3662 /sys/kern/link_elf_obj.c
parentd8bf8e1e8ad280542b4de90763d6d552c4f27b3a (diff)
downloadFreeBSD-src-5bc3a65e406b90cd9e2a47b79117e453bdb56413.zip
FreeBSD-src-5bc3a65e406b90cd9e2a47b79117e453bdb56413.tar.gz
Implement a facility for dynamic per-cpu variables.
- Modules and kernel code alike may use DPCPU_DEFINE(), DPCPU_GET(), DPCPU_SET(), etc. akin to the statically defined PCPU_*. Requires only one extra instruction more than PCPU_* and is virtually the same as __thread for builtin and much faster for shared objects. DPCPU variables can be initialized when defined. - Modules are supported by relocating the module's per-cpu linker set over space reserved in the kernel. Modules may fail to load if there is insufficient space available. - Track space available for modules with a one-off extent allocator. Free may block for memory to allocate space for an extent. Reviewed by: jhb, rwatson, kan, sam, grehan, marius, marcel, stas
Diffstat (limited to 'sys/kern/link_elf_obj.c')
-rw-r--r--sys/kern/link_elf_obj.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 2adbe19..9d4d70c 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -333,6 +333,20 @@ link_elf_link_preload(linker_class_t cls, const char *filename,
if (ef->shstrtab && shdr[i].sh_name != 0)
ef->progtab[pb].name =
ef->shstrtab + shdr[i].sh_name;
+ if (ef->progtab[pb].name != NULL &&
+ !strcmp(ef->progtab[pb].name, "set_pcpu")) {
+ void *dpcpu;
+
+ dpcpu = dpcpu_alloc(shdr[i].sh_size);
+ if (dpcpu == NULL) {
+ error = ENOSPC;
+ goto out;
+ }
+ memcpy(dpcpu, ef->progtab[pb].addr,
+ ef->progtab[pb].size);
+ dpcpu_copy(dpcpu, shdr[i].sh_size);
+ ef->progtab[pb].addr = dpcpu;
+ }
/* Update all symbol values with the offset. */
for (j = 0; j < ef->ddbsymcnt; j++) {
@@ -712,9 +726,27 @@ link_elf_load_file(linker_class_t cls, const char *filename,
alignmask = shdr[i].sh_addralign - 1;
mapbase += alignmask;
mapbase &= ~alignmask;
- ef->progtab[pb].addr = (void *)(uintptr_t)mapbase;
- if (shdr[i].sh_type == SHT_PROGBITS) {
+ if (ef->shstrtab && shdr[i].sh_name != 0)
+ ef->progtab[pb].name =
+ ef->shstrtab + shdr[i].sh_name;
+ else if (shdr[i].sh_type == SHT_PROGBITS)
ef->progtab[pb].name = "<<PROGBITS>>";
+ else
+ ef->progtab[pb].name = "<<NOBITS>>";
+ if (ef->progtab[pb].name != NULL &&
+ !strcmp(ef->progtab[pb].name, "set_pcpu"))
+ ef->progtab[pb].addr =
+ dpcpu_alloc(shdr[i].sh_size);
+ else
+ ef->progtab[pb].addr =
+ (void *)(uintptr_t)mapbase;
+ if (ef->progtab[pb].addr == NULL) {
+ error = ENOSPC;
+ goto out;
+ }
+ ef->progtab[pb].size = shdr[i].sh_size;
+ ef->progtab[pb].sec = i;
+ if (shdr[i].sh_type == SHT_PROGBITS) {
error = vn_rdwr(UIO_READ, nd.ni_vp,
ef->progtab[pb].addr,
shdr[i].sh_size, shdr[i].sh_offset,
@@ -726,15 +758,12 @@ link_elf_load_file(linker_class_t cls, const char *filename,
error = EINVAL;
goto out;
}
- } else {
- ef->progtab[pb].name = "<<NOBITS>>";
+ /* Initialize the per-cpu area. */
+ if (ef->progtab[pb].addr != (void *)mapbase)
+ dpcpu_copy(ef->progtab[pb].addr,
+ shdr[i].sh_size);
+ } else
bzero(ef->progtab[pb].addr, shdr[i].sh_size);
- }
- ef->progtab[pb].size = shdr[i].sh_size;
- ef->progtab[pb].sec = i;
- if (ef->shstrtab && shdr[i].sh_name != 0)
- ef->progtab[pb].name =
- ef->shstrtab + shdr[i].sh_name;
/* Update all symbol values with the offset. */
for (j = 0; j < ef->ddbsymcnt; j++) {
@@ -839,6 +868,17 @@ link_elf_unload_file(linker_file_t file)
/* Notify MD code that a module is being unloaded. */
elf_cpu_unload_file(file);
+ if (ef->progtab) {
+ for (i = 0; i < ef->nprogtab; i++) {
+ if (ef->progtab[i].size == 0)
+ continue;
+ if (ef->progtab[i].name == NULL)
+ continue;
+ if (!strcmp(ef->progtab[i].name, "set_pcpu"))
+ dpcpu_free(ef->progtab[i].addr,
+ ef->progtab[i].size);
+ }
+ }
if (ef->preloaded) {
if (ef->reltab)
free(ef->reltab, M_LINKER);
OpenPOWER on IntegriCloud