Enable the use of VM_PHYSSEG_SPARSE on amd64 and i386, making it the default
on i386 PAE. Previously, VM_PHYSSEG_SPARSE could not be used on amd64 and i386 because vm_page_startup() would not create vm_page structures for the kernel page table pages allocated during pmap_bootstrap() but those vm_page structures are needed when the kernel attempts to promote the corresponding kernel virtual addresses to superpage mappings. To address this problem, a new public function, vm_phys_add_seg(), is introduced and vm_phys_init() is updated to reflect the creation of vm_phys_seg structures by calls to vm_phys_add_seg(). Discussed with: Svatopluk Kraus MFC after: 3 weeks Sponsored by: EMC / Isilon Storage Division
This commit is contained in:
parent
eb81bf559c
commit
271f0f1219
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=274556
@ -833,6 +833,15 @@ pmap_bootstrap(vm_paddr_t *firstaddr)
|
||||
*/
|
||||
create_pagetables(firstaddr);
|
||||
|
||||
/*
|
||||
* Add a physical memory segment (vm_phys_seg) corresponding to the
|
||||
* preallocated kernel page table pages so that vm_page structures
|
||||
* representing these pages will be created. The vm_page structures
|
||||
* are required for promotion of the corresponding kernel virtual
|
||||
* addresses to superpage mappings.
|
||||
*/
|
||||
vm_phys_add_seg(KPTphys, KPTphys + ptoa(nkpt));
|
||||
|
||||
virtual_avail = (vm_offset_t) KERNBASE + *firstaddr;
|
||||
virtual_avail = pmap_kmem_choose(virtual_avail);
|
||||
|
||||
|
@ -374,6 +374,15 @@ pmap_bootstrap(vm_paddr_t firstaddr)
|
||||
struct sysmaps *sysmaps;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add a physical memory segment (vm_phys_seg) corresponding to the
|
||||
* preallocated kernel page table pages so that vm_page structures
|
||||
* representing these pages will be created. The vm_page structures
|
||||
* are required for promotion of the corresponding kernel virtual
|
||||
* addresses to superpage mappings.
|
||||
*/
|
||||
vm_phys_add_seg(KPTphys, KPTphys + ptoa(nkpt));
|
||||
|
||||
/*
|
||||
* Initialize the first available kernel virtual address. However,
|
||||
* using "firstaddr" may waste a few pages of the kernel virtual
|
||||
|
@ -64,9 +64,15 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The physical address space is densely populated.
|
||||
* Choose between DENSE and SPARSE based on whether lower execution time or
|
||||
* lower kernel address space consumption is desired. Under PAE, kernel
|
||||
* address space is often in short supply.
|
||||
*/
|
||||
#ifdef PAE
|
||||
#define VM_PHYSSEG_SPARSE
|
||||
#else
|
||||
#define VM_PHYSSEG_DENSE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The number of PHYSSEG entries must be one greater than the number
|
||||
|
@ -304,9 +304,23 @@ vm_page_startup(vm_offset_t vaddr)
|
||||
phys_avail[i + 1] = trunc_page(phys_avail[i + 1]);
|
||||
}
|
||||
|
||||
#ifdef XEN
|
||||
/*
|
||||
* There is no obvious reason why i386 PV Xen needs vm_page structs
|
||||
* created for these pseudo-physical addresses. XXX
|
||||
*/
|
||||
vm_phys_add_seg(0, phys_avail[0]);
|
||||
#endif
|
||||
|
||||
low_water = phys_avail[0];
|
||||
high_water = phys_avail[1];
|
||||
|
||||
for (i = 0; i < vm_phys_nsegs; i++) {
|
||||
if (vm_phys_segs[i].start < low_water)
|
||||
low_water = vm_phys_segs[i].start;
|
||||
if (vm_phys_segs[i].end > high_water)
|
||||
high_water = vm_phys_segs[i].end;
|
||||
}
|
||||
for (i = 0; phys_avail[i + 1]; i += 2) {
|
||||
vm_paddr_t size = phys_avail[i + 1] - phys_avail[i];
|
||||
|
||||
@ -320,10 +334,6 @@ vm_page_startup(vm_offset_t vaddr)
|
||||
high_water = phys_avail[i + 1];
|
||||
}
|
||||
|
||||
#ifdef XEN
|
||||
low_water = 0;
|
||||
#endif
|
||||
|
||||
end = phys_avail[biggestone+1];
|
||||
|
||||
/*
|
||||
@ -391,6 +401,10 @@ vm_page_startup(vm_offset_t vaddr)
|
||||
first_page = low_water / PAGE_SIZE;
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
page_range = 0;
|
||||
for (i = 0; i < vm_phys_nsegs; i++) {
|
||||
page_range += atop(vm_phys_segs[i].end -
|
||||
vm_phys_segs[i].start);
|
||||
}
|
||||
for (i = 0; phys_avail[i + 1] != 0; i += 2)
|
||||
page_range += atop(phys_avail[i + 1] - phys_avail[i]);
|
||||
#elif defined(VM_PHYSSEG_DENSE)
|
||||
@ -432,6 +446,13 @@ vm_page_startup(vm_offset_t vaddr)
|
||||
#endif
|
||||
phys_avail[biggestone + 1] = new_end;
|
||||
|
||||
/*
|
||||
* Add physical memory segments corresponding to the available
|
||||
* physical pages.
|
||||
*/
|
||||
for (i = 0; phys_avail[i + 1] != 0; i += 2)
|
||||
vm_phys_add_seg(phys_avail[i], phys_avail[i + 1]);
|
||||
|
||||
/*
|
||||
* Clear all of the page structures
|
||||
*/
|
||||
|
103
sys/vm/vm_phys.c
103
sys/vm/vm_phys.c
@ -301,29 +301,19 @@ static void
|
||||
_vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind, int domain)
|
||||
{
|
||||
struct vm_phys_seg *seg;
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
long pages;
|
||||
int segind;
|
||||
|
||||
pages = 0;
|
||||
for (segind = 0; segind < vm_phys_nsegs; segind++) {
|
||||
seg = &vm_phys_segs[segind];
|
||||
pages += atop(seg->end - seg->start);
|
||||
}
|
||||
#endif
|
||||
KASSERT(vm_phys_nsegs < VM_PHYSSEG_MAX,
|
||||
("vm_phys_create_seg: increase VM_PHYSSEG_MAX"));
|
||||
KASSERT(domain < vm_ndomains,
|
||||
("vm_phys_create_seg: invalid domain provided"));
|
||||
seg = &vm_phys_segs[vm_phys_nsegs++];
|
||||
while (seg > vm_phys_segs && (seg - 1)->start >= end) {
|
||||
*seg = *(seg - 1);
|
||||
seg--;
|
||||
}
|
||||
seg->start = start;
|
||||
seg->end = end;
|
||||
seg->domain = domain;
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
seg->first_page = &vm_page_array[pages];
|
||||
#else
|
||||
seg->first_page = PHYS_TO_VM_PAGE(start);
|
||||
#endif
|
||||
seg->free_queues = &vm_phys_free_queues[domain][flind];
|
||||
}
|
||||
|
||||
@ -356,6 +346,45 @@ vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a physical memory segment.
|
||||
*/
|
||||
void
|
||||
vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end)
|
||||
{
|
||||
|
||||
KASSERT((start & PAGE_MASK) == 0,
|
||||
("vm_phys_define_seg: start is not page aligned"));
|
||||
KASSERT((end & PAGE_MASK) == 0,
|
||||
("vm_phys_define_seg: end is not page aligned"));
|
||||
#ifdef VM_FREELIST_ISADMA
|
||||
if (start < 16777216) {
|
||||
if (end > 16777216) {
|
||||
vm_phys_create_seg(start, 16777216,
|
||||
VM_FREELIST_ISADMA);
|
||||
vm_phys_create_seg(16777216, end, VM_FREELIST_DEFAULT);
|
||||
} else
|
||||
vm_phys_create_seg(start, end, VM_FREELIST_ISADMA);
|
||||
if (VM_FREELIST_ISADMA >= vm_nfreelists)
|
||||
vm_nfreelists = VM_FREELIST_ISADMA + 1;
|
||||
} else
|
||||
#endif
|
||||
#ifdef VM_FREELIST_HIGHMEM
|
||||
if (end > VM_HIGHMEM_ADDRESS) {
|
||||
if (start < VM_HIGHMEM_ADDRESS) {
|
||||
vm_phys_create_seg(start, VM_HIGHMEM_ADDRESS,
|
||||
VM_FREELIST_DEFAULT);
|
||||
vm_phys_create_seg(VM_HIGHMEM_ADDRESS, end,
|
||||
VM_FREELIST_HIGHMEM);
|
||||
} else
|
||||
vm_phys_create_seg(start, end, VM_FREELIST_HIGHMEM);
|
||||
if (VM_FREELIST_HIGHMEM >= vm_nfreelists)
|
||||
vm_nfreelists = VM_FREELIST_HIGHMEM + 1;
|
||||
} else
|
||||
#endif
|
||||
vm_phys_create_seg(start, end, VM_FREELIST_DEFAULT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the physical memory allocator.
|
||||
*/
|
||||
@ -363,41 +392,23 @@ void
|
||||
vm_phys_init(void)
|
||||
{
|
||||
struct vm_freelist *fl;
|
||||
int dom, flind, i, oind, pind;
|
||||
struct vm_phys_seg *seg;
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
long pages;
|
||||
#endif
|
||||
int dom, flind, oind, pind, segind;
|
||||
|
||||
for (i = 0; phys_avail[i + 1] != 0; i += 2) {
|
||||
#ifdef VM_FREELIST_ISADMA
|
||||
if (phys_avail[i] < 16777216) {
|
||||
if (phys_avail[i + 1] > 16777216) {
|
||||
vm_phys_create_seg(phys_avail[i], 16777216,
|
||||
VM_FREELIST_ISADMA);
|
||||
vm_phys_create_seg(16777216, phys_avail[i + 1],
|
||||
VM_FREELIST_DEFAULT);
|
||||
} else {
|
||||
vm_phys_create_seg(phys_avail[i],
|
||||
phys_avail[i + 1], VM_FREELIST_ISADMA);
|
||||
}
|
||||
if (VM_FREELIST_ISADMA >= vm_nfreelists)
|
||||
vm_nfreelists = VM_FREELIST_ISADMA + 1;
|
||||
} else
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
pages = 0;
|
||||
#endif
|
||||
#ifdef VM_FREELIST_HIGHMEM
|
||||
if (phys_avail[i + 1] > VM_HIGHMEM_ADDRESS) {
|
||||
if (phys_avail[i] < VM_HIGHMEM_ADDRESS) {
|
||||
vm_phys_create_seg(phys_avail[i],
|
||||
VM_HIGHMEM_ADDRESS, VM_FREELIST_DEFAULT);
|
||||
vm_phys_create_seg(VM_HIGHMEM_ADDRESS,
|
||||
phys_avail[i + 1], VM_FREELIST_HIGHMEM);
|
||||
} else {
|
||||
vm_phys_create_seg(phys_avail[i],
|
||||
phys_avail[i + 1], VM_FREELIST_HIGHMEM);
|
||||
}
|
||||
if (VM_FREELIST_HIGHMEM >= vm_nfreelists)
|
||||
vm_nfreelists = VM_FREELIST_HIGHMEM + 1;
|
||||
} else
|
||||
for (segind = 0; segind < vm_phys_nsegs; segind++) {
|
||||
seg = &vm_phys_segs[segind];
|
||||
#ifdef VM_PHYSSEG_SPARSE
|
||||
seg->first_page = &vm_page_array[pages];
|
||||
pages += atop(seg->end - seg->start);
|
||||
#else
|
||||
seg->first_page = PHYS_TO_VM_PAGE(seg->start);
|
||||
#endif
|
||||
vm_phys_create_seg(phys_avail[i], phys_avail[i + 1],
|
||||
VM_FREELIST_DEFAULT);
|
||||
}
|
||||
for (dom = 0; dom < vm_ndomains; dom++) {
|
||||
for (flind = 0; flind < vm_nfreelists; flind++) {
|
||||
|
@ -69,6 +69,7 @@ extern int vm_phys_nsegs;
|
||||
* The following functions are only to be used by the virtual memory system.
|
||||
*/
|
||||
void vm_phys_add_page(vm_paddr_t pa);
|
||||
void vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end);
|
||||
vm_page_t vm_phys_alloc_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary);
|
||||
vm_page_t vm_phys_alloc_freelist_pages(int flind, int pool, int order);
|
||||
|
Loading…
Reference in New Issue
Block a user