Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/i386 Use a bitmap-based allocator for i386, same as...
details: https://anonhg.NetBSD.org/src/rev/5ecd983db733
branches: trunk
changeset: 354865:5ecd983db733
user: maxv <maxv%NetBSD.org@localhost>
date: Sun Jul 02 11:16:50 2017 +0000
description:
Use a bitmap-based allocator for i386, same as amd64. Several functions
are now identical - or nearly identical - on both sides. I couldn't test
this change on xen, because I'm having some unrelated issues with my VM
and I've spent enough time not understanding what's wrong with it.
diffstat:
sys/arch/i386/i386/gdt.c | 153 ++++++++++++++++++--------------------
sys/arch/i386/include/segments.h | 12 ++-
2 files changed, 84 insertions(+), 81 deletions(-)
diffs (truncated from 339 to 300 lines):
diff -r f08c93a5201f -r 5ecd983db733 sys/arch/i386/i386/gdt.c
--- a/sys/arch/i386/i386/gdt.c Sun Jul 02 10:52:35 2017 +0000
+++ b/sys/arch/i386/i386/gdt.c Sun Jul 02 11:16:50 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: gdt.c,v 1.62 2017/07/02 09:02:06 maxv Exp $ */
+/* $NetBSD: gdt.c,v 1.63 2017/07/02 11:16:50 maxv Exp $ */
/*
* Copyright (c) 1996, 1997, 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.62 2017/07/02 09:02:06 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.63 2017/07/02 11:16:50 maxv Exp $");
#include "opt_multiprocessor.h"
#include "opt_xen.h"
@@ -45,10 +45,18 @@
#include <machine/gdt.h>
-int gdt_size; /* total number of GDT entries */
-int gdt_count; /* number of GDT entries in use */
-int gdt_next; /* next available slot for sweeping */
-int gdt_free; /* next free slot; terminated with GNULL_SEL */
+#define NSLOTS(sz) \
+ ((sz - DYNSEL_START) / sizeof(union descriptor))
+
+#define NDYNSLOTS NSLOTS(MAXGDTSIZ)
+
+typedef struct {
+ bool busy[NDYNSLOTS];
+ size_t nslots;
+} gdt_bitmap_t;
+
+size_t gdt_size; /* size of GDT in bytes */
+static gdt_bitmap_t gdt_bitmap; /* bitmap of busy slots */
#ifndef XEN
static int ldt_count; /* number of LDTs */
@@ -81,17 +89,20 @@
* Called on a newly-allocated GDT slot, so no race between CPUs.
*/
static void
-setgdt(int sel, const void *base, size_t limit, int type, int dpl, int def32,
+setgdt(int slot, const void *base, size_t limit, int type, int dpl, int def32,
int gran)
{
- struct segment_descriptor *sd = &gdtstore[sel].sd;
+ struct segment_descriptor *sd;
CPU_INFO_ITERATOR cii;
struct cpu_info *ci;
+ int idx;
+ idx = IDXSEL(GDYNSEL(slot, SEL_KPL));
+ sd = &gdtstore[idx].sd;
setsegment(sd, base, limit, type, dpl, def32, gran);
for (CPU_INFO_FOREACH(cii, ci)) {
if (ci->ci_gdt != NULL)
- update_descriptor(&ci->ci_gdt[sel],
+ update_descriptor(&ci->ci_gdt[idx],
(union descriptor *)sd);
}
}
@@ -104,24 +115,27 @@
void
gdt_init(void)
{
- size_t max_len, min_len;
union descriptor *old_gdt;
struct vm_page *pg;
vaddr_t va;
struct cpu_info *ci = &cpu_info_primary;
- max_len = MAXGDTSIZ;
- min_len = MINGDTSIZ;
-
- gdt_size = (MINGDTSIZ / sizeof(gdtstore[0]));
- gdt_count = NGDT;
- gdt_next = NGDT;
- gdt_free = GNULL_SEL;
+ /* Initialize the global values */
+ gdt_size = MINGDTSIZ;
+ memset(&gdt_bitmap.busy, 0, sizeof(gdt_bitmap.busy));
+ gdt_bitmap.nslots = NSLOTS(gdt_size);
old_gdt = gdtstore;
- gdtstore = (union descriptor *)uvm_km_alloc(kernel_map, max_len,
- 0, UVM_KMF_VAONLY);
- for (va = (vaddr_t)gdtstore; va < (vaddr_t)gdtstore + min_len;
+
+ /* Allocate MAXGDTSIZ bytes of virtual memory. */
+ gdtstore = (union descriptor *)uvm_km_alloc(kernel_map, MAXGDTSIZ, 0,
+ UVM_KMF_VAONLY);
+
+ /*
+ * Allocate only MINGDTSIZ bytes of physical memory. We will grow this
+ * area in gdt_grow at run-time if needed.
+ */
+ for (va = (vaddr_t)gdtstore; va < (vaddr_t)gdtstore + MINGDTSIZ;
va += PAGE_SIZE) {
pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
if (pg == NULL) {
@@ -131,6 +145,8 @@
VM_PROT_READ | VM_PROT_WRITE, 0);
}
pmap_update(pmap_kernel());
+
+ /* Copy the initial bootstrap GDT into the new area. */
memcpy(gdtstore, old_gdt, NGDT * sizeof(gdtstore[0]));
ci->ci_gdt = gdtstore;
setsegment(&ci->ci_gdt[GCPU_SEL].sd, ci,
@@ -153,6 +169,7 @@
ci->ci_gdt = (union descriptor *)uvm_km_alloc(kernel_map, max_len,
0, UVM_KMF_VAONLY);
+
for (va = (vaddr_t)ci->ci_gdt; va < (vaddr_t)ci->ci_gdt + min_len;
va += PAGE_SIZE) {
while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO))
@@ -163,8 +180,10 @@
VM_PROT_READ | VM_PROT_WRITE, 0);
}
pmap_update(pmap_kernel());
+
memset(ci->ci_gdt, 0, min_len);
- memcpy(ci->ci_gdt, gdtstore, gdt_count * sizeof(gdtstore[0]));
+ memcpy(ci->ci_gdt, gdtstore, gdt_size);
+
setsegment(&ci->ci_gdt[GCPU_SEL].sd, ci,
sizeof(struct cpu_info) - 1, SDT_MEMRWA, SEL_KPL, 1, 0);
}
@@ -184,11 +203,11 @@
setregion(®ion, ci->ci_gdt, max_len - 1);
lgdt(®ion);
#else
- size_t len = gdt_size * sizeof(gdtstore[0]);
+ size_t len = gdt_size;
unsigned long frames[len >> PAGE_SHIFT];
vaddr_t va;
pt_entry_t *ptp;
- int f;
+ size_t f;
for (va = (vaddr_t)ci->ci_gdt, f = 0; va < (vaddr_t)ci->ci_gdt + len;
va += PAGE_SIZE, f++) {
@@ -197,13 +216,13 @@
frames[f] = *ptp >> PAGE_SHIFT;
/*
- * pmap_pte_clearbits(ptp, PG_RW);
- * but without spl(), since %fs is not setup
- * properly yet, ie; curcpu() won't work at this
- * point and spl() will break.
+ * Our own
+ * pmap_pte_clearbits(ptp, PG_RW)
+ * but without spl(), since %fs is not set up properly yet; ie
+ * curcpu() won't work at this point and spl() will break.
*/
if (HYPERVISOR_update_va_mapping((vaddr_t)va,
- *ptp & ~PG_RW, UVMF_INVLPG) < 0) {
+ *ptp & ~PG_RW, UVMF_INVLPG) < 0) {
panic("%s page RO update failed.\n", __func__);
}
}
@@ -220,22 +239,24 @@
* of them. We already have the virtual memory, we only need to grow the
* physical memory.
*/
-void
+static void
gdt_grow(void)
{
- size_t old_len, new_len;
+ size_t old_size;
CPU_INFO_ITERATOR cii;
struct cpu_info *ci;
struct vm_page *pg;
vaddr_t va;
- old_len = gdt_size * sizeof(gdtstore[0]);
- gdt_size <<= 1;
- new_len = old_len << 1;
+ old_size = gdt_size;
+ gdt_size *= 2;
+ if (gdt_size > MAXGDTSIZ)
+ gdt_size = MAXGDTSIZ;
+ gdt_bitmap.nslots = NSLOTS(gdt_size);
for (CPU_INFO_FOREACH(cii, ci)) {
- for (va = (vaddr_t)(ci->ci_gdt) + old_len;
- va < (vaddr_t)(ci->ci_gdt) + new_len;
+ for (va = (vaddr_t)(ci->ci_gdt) + old_size;
+ va < (vaddr_t)(ci->ci_gdt) + gdt_size;
va += PAGE_SIZE) {
while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO)) ==
NULL) {
@@ -249,60 +270,34 @@
pmap_update(pmap_kernel());
}
-/*
- * Allocate a GDT slot as follows:
- * 1) If there are entries on the free list, use those.
- * 2) If there are fewer than gdt_size entries in use, there are free slots
- * near the end that we can sweep through.
- * 3) As a last resort, we increase the size of the GDT, and sweep through
- * the new slots.
- */
static int
gdt_get_slot(void)
{
- int slot;
- size_t offset;
+ size_t i;
KASSERT(mutex_owned(&cpu_lock));
- if (gdt_free != GNULL_SEL) {
- slot = gdt_free;
- gdt_free = gdtstore[slot].gd.gd_selector;
- } else {
- offset = 0;
- if (gdt_next != gdt_count + offset)
- panic("gdt_get_slot botch 1");
- if (gdt_next - offset >= gdt_size) {
- if (gdt_size >= (MAXGDTSIZ / sizeof(gdtstore[0])))
- panic("gdt_get_slot botch 2");
- gdt_grow();
+ while (1) {
+ for (i = 0; i < gdt_bitmap.nslots; i++) {
+ if (!gdt_bitmap.busy[i]) {
+ gdt_bitmap.busy[i] = true;
+ return (int)i;
+ }
}
- slot = gdt_next++;
+ if (gdt_size >= MAXGDTSIZ)
+ panic("gdt_get_slot: out of memory");
+ gdt_grow();
}
-
- gdt_count++;
- return (slot);
+ /* NOTREACHED */
+ return 0;
}
-/*
- * Deallocate a GDT slot, putting it on the free list.
- */
static void
gdt_put_slot(int slot)
{
- union descriptor d;
- d.raw[0] = 0;
- d.raw[1] = 0;
-
KASSERT(mutex_owned(&cpu_lock));
-
- gdt_count--;
-
- d.gd.gd_type = SDT_SYSNULL;
- d.gd.gd_selector = gdt_free;
- update_descriptor(&gdtstore[slot], &d);
-
- gdt_free = slot;
+ KASSERT(slot < gdt_bitmap.nslots);
+ gdt_bitmap.busy[slot] = false;
}
int
@@ -316,7 +311,7 @@
SDT_SYS386TSS, SEL_KPL, 0, 0);
mutex_exit(&cpu_lock);
- return GSEL(slot, SEL_KPL);
+ return GDYNSEL(slot, SEL_KPL);
}
void
@@ -324,7 +319,7 @@
{
mutex_enter(&cpu_lock);
- gdt_put_slot(IDXSEL(sel));
+ gdt_put_slot(IDXDYNSEL(sel));
mutex_exit(&cpu_lock);
}
@@ -343,7 +338,7 @@
slot = gdt_get_slot();
setgdt(slot, ldtp, len - 1, SDT_SYSLDT, SEL_KPL, 0, 0);
- return GSEL(slot, SEL_KPL);
+ return GDYNSEL(slot, SEL_KPL);
}
void
Home |
Main Index |
Thread Index |
Old Index