1/* $NetBSD: t_uvm_physseg.c,v 1.2 2016/12/22 08:15:20 cherry Exp $ */
2
3/*-
4 * Copyright (c) 2015, 2016 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Santhosh N. Raju <santhosh.raju@gmail.com> and
9 * by Cherry G. Mathew
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__RCSID("$NetBSD: t_uvm_physseg.c,v 1.2 2016/12/22 08:15:20 cherry Exp $");
35
36/*
37 * If this line is commented out tests related to uvm_physseg_get_pmseg()
38 * wont run.
39 *
40 * Have a look at machine/uvm_physseg.h for more details.
41 */
42#define __HAVE_PMAP_PHYSSEG
43
44/*
45 * This is a dummy struct used for testing purposes
46 *
47 * In reality this struct would exist in the MD part of the code residing in
48 * machines/vmparam.h
49 */
50
51#ifdef __HAVE_PMAP_PHYSSEG
52struct pmap_physseg {
53	int dummy_variable;		/* Dummy variable use for testing */
54};
55#endif
56
57/* Testing API - assumes userland */
58/* Provide Kernel API equivalents */
59#include <assert.h>
60#include <errno.h>
61#include <stdbool.h>
62#include <string.h> /* memset(3) et. al */
63#include <stdio.h> /* printf(3) */
64#include <stdlib.h> /* malloc(3) */
65#include <stdarg.h>
66#include <stddef.h>
67
68#define	PRIxPADDR	"lx"
69#define	PRIxPSIZE	"lx"
70#define	PRIuPSIZE	"lu"
71#define	PRIxVADDR	"lx"
72#define	PRIxVSIZE	"lx"
73#define	PRIuVSIZE	"lu"
74
75#define UVM_HOTPLUG /* Enable hotplug with rbtree. */
76#define PMAP_STEAL_MEMORY
77#define DEBUG /* Enable debug functionality. */
78
79typedef unsigned long vaddr_t;
80typedef unsigned long paddr_t;
81typedef unsigned long psize_t;
82typedef unsigned long vsize_t;
83
84#include <uvm/uvm_physseg.h>
85#include <uvm/uvm_page.h>
86
87#ifndef DIAGNOSTIC
88#define	KASSERTMSG(e, msg, ...)	/* NOTHING */
89#define	KASSERT(e)		/* NOTHING */
90#else
91#define	KASSERT(a)		assert(a)
92#define KASSERTMSG(exp, ...)    printf(__VA_ARGS__); assert((exp))
93#endif
94
95#define VM_PHYSSEG_STRAT VM_PSTRAT_BSEARCH
96
97#define VM_NFREELIST            4
98#define VM_FREELIST_DEFAULT     0
99#define VM_FREELIST_FIRST16     3
100#define VM_FREELIST_FIRST1G     2
101#define VM_FREELIST_FIRST4G     1
102
103/*
104 * Used in tests when Array implementation is tested
105 */
106#if !defined(VM_PHYSSEG_MAX)
107#define VM_PHYSSEG_MAX          1
108#endif
109
110#define PAGE_SHIFT              12
111#define PAGE_SIZE               (1 << PAGE_SHIFT)
112#define	PAGE_MASK	(PAGE_SIZE - 1)
113#define atop(x)         (((paddr_t)(x)) >> PAGE_SHIFT)
114#define ptoa(x)         (((paddr_t)(x)) << PAGE_SHIFT)
115
116#define	mutex_enter(l)
117#define	mutex_exit(l)
118
119psize_t physmem;
120
121struct uvmexp uvmexp;        /* decl */
122
123/*
124 * uvm structure borrowed from uvm.h
125 *
126 * Remember this is a dummy structure used within the ATF Tests and
127 * uses only necessary fields from the original uvm struct.
128 * See uvm/uvm.h for the full struct.
129 */
130
131struct uvm {
132	/* vm_page related parameters */
133
134	bool page_init_done;		/* TRUE if uvm_page_init() finished */
135} uvm;
136
137#include <sys/kmem.h>
138
139void *
140kmem_alloc(size_t size, km_flag_t flags)
141{
142	return malloc(size);
143}
144
145void *
146kmem_zalloc(size_t size, km_flag_t flags)
147{
148	void *ptr;
149	ptr = malloc(size);
150
151	memset(ptr, 0, size);
152
153	return ptr;
154}
155
156void
157kmem_free(void *mem, size_t size)
158{
159	free(mem);
160}
161
162static void
163panic(const char *fmt, ...)
164{
165	va_list ap;
166
167	va_start(ap, fmt);
168	vprintf(fmt, ap);
169	printf("\n");
170	va_end(ap);
171	KASSERT(false);
172
173	/*NOTREACHED*/
174}
175
176static void
177uvm_pagefree(struct vm_page *pg)
178{
179	return;
180}
181
182#if defined(UVM_HOTPLUG)
183static void
184uvmpdpol_reinit(void)
185{
186	return;
187}
188#endif /* UVM_HOTPLUG */
189
190/* end - Provide Kernel API equivalents */
191
192
193#include "uvm/uvm_physseg.c"
194
195#include <atf-c.h>
196
197#define SIXTYFOUR_KILO (64 * 1024)
198#define ONETWENTYEIGHT_KILO (128 * 1024)
199#define TWOFIFTYSIX_KILO (256 * 1024)
200#define FIVEONETWO_KILO (512 * 1024)
201#define ONE_MEGABYTE (1024 * 1024)
202#define TWO_MEGABYTE (2 * 1024 * 1024)
203
204/* Sample Page Frame Numbers */
205#define VALID_START_PFN_1 atop(0)
206#define VALID_END_PFN_1 atop(ONE_MEGABYTE)
207#define VALID_AVAIL_START_PFN_1 atop(0)
208#define VALID_AVAIL_END_PFN_1 atop(ONE_MEGABYTE)
209
210#define VALID_START_PFN_2 atop(ONE_MEGABYTE + 1)
211#define VALID_END_PFN_2 atop(ONE_MEGABYTE * 2)
212#define VALID_AVAIL_START_PFN_2 atop(ONE_MEGABYTE + 1)
213#define VALID_AVAIL_END_PFN_2 atop(ONE_MEGABYTE * 2)
214
215#define VALID_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
216#define VALID_END_PFN_3 atop(ONE_MEGABYTE * 3)
217#define VALID_AVAIL_START_PFN_3 atop((ONE_MEGABYTE * 2) + 1)
218#define VALID_AVAIL_END_PFN_3 atop(ONE_MEGABYTE * 3)
219
220#define VALID_START_PFN_4 atop((ONE_MEGABYTE * 3) + 1)
221#define VALID_END_PFN_4 atop(ONE_MEGABYTE * 4)
222#define VALID_AVAIL_START_PFN_4 atop((ONE_MEGABYTE * 3) + 1)
223#define VALID_AVAIL_END_PFN_4 atop(ONE_MEGABYTE * 4)
224
225/*
226 * Total number of pages (of 4K size each) should be 256 for 1MB of memory.
227 */
228#define PAGE_COUNT_1M      256
229
230/*
231 * A debug fucntion to print the content of upm.
232 */
233	static inline void
234	uvm_physseg_dump_seg(uvm_physseg_t upm)
235	{
236#if defined(DEBUG)
237		printf("%s: seg->start == %ld\n", __func__,
238		    uvm_physseg_get_start(upm));
239		printf("%s: seg->end == %ld\n", __func__,
240		    uvm_physseg_get_end(upm));
241		printf("%s: seg->avail_start == %ld\n", __func__,
242		    uvm_physseg_get_avail_start(upm));
243		printf("%s: seg->avail_end == %ld\n", __func__,
244		    uvm_physseg_get_avail_end(upm));
245
246		printf("====\n\n");
247#else
248		return;
249#endif /* DEBUG */
250	}
251
252/*
253 * Private accessor that gets the value of uvm_physseg_graph.nentries
254 */
255static int
256uvm_physseg_get_entries(void)
257{
258#if defined(UVM_HOTPLUG)
259	return uvm_physseg_graph.nentries;
260#else
261	return vm_nphysmem;
262#endif /* UVM_HOTPLUG */
263}
264
265#if !defined(UVM_HOTPLUG)
266static void *
267uvm_physseg_alloc(size_t sz)
268{
269	return &vm_physmem[vm_nphysseg++];
270}
271#endif
272
273/*
274 * Test Fixture SetUp().
275 */
276static void
277setup(void)
278{
279	/* Prerequisites for running certain calls in uvm_physseg */
280	uvmexp.pagesize = PAGE_SIZE;
281	uvmexp.npages = 0;
282	uvm.page_init_done = false;
283	uvm_physseg_init();
284}
285
286
287/* <---- Tests for Internal functions ----> */
288#if defined(UVM_HOTPLUG)
289ATF_TC(uvm_physseg_alloc_atboot_mismatch);
290ATF_TC_HEAD(uvm_physseg_alloc_atboot_mismatch, tc)
291{
292	atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_alloc() sanity"
293	    "size mismatch alloc() test.");
294}
295
296ATF_TC_BODY(uvm_physseg_alloc_atboot_mismatch, tc)
297{
298	uvm.page_init_done = false;
299
300	atf_tc_expect_signal(SIGABRT, "size mismatch alloc()");
301
302	uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1);
303}
304
305ATF_TC(uvm_physseg_alloc_atboot_overrun);
306ATF_TC_HEAD(uvm_physseg_alloc_atboot_overrun, tc)
307{
308	atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_alloc() sanity"
309	    "array overrun alloc() test.");
310}
311
312ATF_TC_BODY(uvm_physseg_alloc_atboot_overrun, tc)
313{
314	uvm.page_init_done = false;
315
316	atf_tc_expect_signal(SIGABRT, "array overrun alloc()");
317
318	uvm_physseg_alloc((VM_PHYSSEG_MAX + 1) * sizeof(struct uvm_physseg));
319
320}
321
322ATF_TC(uvm_physseg_alloc_sanity);
323ATF_TC_HEAD(uvm_physseg_alloc_sanity, tc)
324{
325	atf_tc_set_md_var(tc, "descr", "further uvm_physseg_alloc() sanity checks");
326}
327
328ATF_TC_BODY(uvm_physseg_alloc_sanity, tc)
329{
330
331	/* At boot time */
332	uvm.page_init_done = false;
333
334	/* Correct alloc */
335	ATF_REQUIRE(uvm_physseg_alloc(VM_PHYSSEG_MAX * sizeof(struct uvm_physseg)));
336
337	/* Retry static alloc()s as dynamic - we expect them to pass */
338	uvm.page_init_done = true;
339	ATF_REQUIRE(uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1));
340	ATF_REQUIRE(uvm_physseg_alloc(2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg)));
341}
342
343ATF_TC(uvm_physseg_free_atboot_mismatch);
344ATF_TC_HEAD(uvm_physseg_free_atboot_mismatch, tc)
345{
346	atf_tc_set_md_var(tc, "descr", "boot time uvm_physseg_free() sanity"
347	    "size mismatch free() test.");
348}
349
350ATF_TC_BODY(uvm_physseg_free_atboot_mismatch, tc)
351{
352	uvm.page_init_done = false;
353
354	atf_tc_expect_signal(SIGABRT, "size mismatch free()");
355
356	uvm_physseg_free(&uvm_physseg[0], sizeof(struct uvm_physseg) - 1);
357}
358
359ATF_TC(uvm_physseg_free_sanity);
360ATF_TC_HEAD(uvm_physseg_free_sanity, tc)
361{
362	atf_tc_set_md_var(tc, "descr", "further uvm_physseg_free() sanity checks");
363}
364
365ATF_TC_BODY(uvm_physseg_free_sanity, tc)
366{
367
368	/* At boot time */
369	uvm.page_init_done = false;
370
371	struct uvm_physseg *seg;
372
373#if VM_PHYSSEG_MAX > 1
374	/*
375	 * Note: free()ing the entire array is considered to be an
376	 * error. Thus VM_PHYSSEG_MAX - 1.
377	 */
378
379	seg = uvm_physseg_alloc((VM_PHYSSEG_MAX - 1) * sizeof(*seg));
380	uvm_physseg_free(seg, (VM_PHYSSEG_MAX - 1) * sizeof(struct uvm_physseg));
381#endif
382
383	/* Retry static alloc()s as dynamic - we expect them to pass */
384	uvm.page_init_done = true;
385
386	seg = uvm_physseg_alloc(sizeof(struct uvm_physseg) - 1);
387	uvm_physseg_free(seg, sizeof(struct uvm_physseg) - 1);
388
389	seg = uvm_physseg_alloc(2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg));
390
391	uvm_physseg_free(seg, 2 * VM_PHYSSEG_MAX * sizeof(struct uvm_physseg));
392}
393
394#if VM_PHYSSEG_MAX > 1
395ATF_TC(uvm_physseg_atboot_free_leak);
396ATF_TC_HEAD(uvm_physseg_atboot_free_leak, tc)
397{
398	atf_tc_set_md_var(tc, "descr",
399	    "does free() leak at boot ?\n"
400	    "This test needs VM_PHYSSEG_MAX > 1)");
401}
402
403ATF_TC_BODY(uvm_physseg_atboot_free_leak, tc)
404{
405
406	/* At boot time */
407	uvm.page_init_done = false;
408
409	/* alloc to array size */
410	struct uvm_physseg *seg;
411	seg = uvm_physseg_alloc(VM_PHYSSEG_MAX * sizeof(*seg));
412
413	uvm_physseg_free(seg, sizeof(*seg));
414
415	atf_tc_expect_signal(SIGABRT, "array overrun on alloc() after leak");
416
417	ATF_REQUIRE(uvm_physseg_alloc(sizeof(struct uvm_physseg)));
418}
419#endif /* VM_PHYSSEG_MAX */
420#endif /* UVM_HOTPLUG */
421
422/*
423 * Note: This function replicates verbatim what happens in
424 * uvm_page.c:uvm_page_init().
425 *
426 * Please track any changes that happen there.
427 */
428static void
429uvm_page_init_fake(struct vm_page *pagearray, psize_t pagecount)
430{
431	uvm_physseg_t bank;
432	size_t n;
433
434	for (bank = uvm_physseg_get_first(),
435		 uvm_physseg_seg_chomp_slab(bank, pagearray, pagecount);
436	     uvm_physseg_valid_p(bank);
437	     bank = uvm_physseg_get_next(bank)) {
438
439		n = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank);
440		uvm_physseg_seg_alloc_from_slab(bank, n);
441		uvm_physseg_init_seg(bank, pagearray);
442
443		/* set up page array pointers */
444		pagearray += n;
445		pagecount -= n;
446	}
447
448	uvm.page_init_done = true;
449}
450
451ATF_TC(uvm_physseg_plug);
452ATF_TC_HEAD(uvm_physseg_plug, tc)
453{
454	atf_tc_set_md_var(tc, "descr",
455	    "Test plug functionality.");
456}
457/* Note: We only do the second boot time plug if VM_PHYSSEG_MAX > 1 */
458ATF_TC_BODY(uvm_physseg_plug, tc)
459{
460	int nentries = 0; /* Count of entries via plug done so far */
461	uvm_physseg_t upm1;
462#if VM_PHYSSEG_MAX > 2
463	uvm_physseg_t upm2;
464#endif
465
466#if VM_PHYSSEG_MAX > 1
467	uvm_physseg_t upm3;
468#endif
469	uvm_physseg_t upm4;
470	psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
471	psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
472	psize_t npages3 = (VALID_END_PFN_3 - VALID_START_PFN_3);
473	psize_t npages4 = (VALID_END_PFN_4 - VALID_START_PFN_4);
474	struct vm_page *pgs, *slab = malloc(sizeof(struct vm_page) * (npages1
475#if VM_PHYSSEG_MAX > 2
476		+ npages2
477#endif
478		+ npages3));
479
480	/* Fake early boot */
481
482	setup();
483
484	/* Vanilla plug x 2 */
485	ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_1, npages1, &upm1), true);
486	ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
487	ATF_REQUIRE_EQ(0, uvmexp.npages);
488
489#if VM_PHYSSEG_MAX > 2
490	ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_2, npages2, &upm2), true);
491	ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
492	ATF_REQUIRE_EQ(0, uvmexp.npages);
493#endif
494	/* Post boot: Fake all segments and pages accounted for. */
495	uvm_page_init_fake(slab, npages1 + npages2 + npages3);
496
497	ATF_CHECK_EQ(npages1
498#if VM_PHYSSEG_MAX > 2
499	    + npages2
500#endif
501	    , uvmexp.npages);
502#if VM_PHYSSEG_MAX > 1
503	/* Scavenge plug - goes into the same slab */
504	ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_3, npages3, &upm3), true);
505	ATF_REQUIRE_EQ(++nentries, uvm_physseg_get_entries());
506	ATF_REQUIRE_EQ(npages1
507#if VM_PHYSSEG_MAX > 2
508	    + npages2
509#endif
510	    + npages3, uvmexp.npages);
511
512	/* Scavenge plug should fit right in the slab */
513	pgs = uvm_physseg_get_pg(upm3, 0);
514	ATF_REQUIRE(pgs > slab && pgs < (slab + npages1 + npages2 + npages3));
515#endif
516	/* Hot plug - goes into a brand new slab */
517	ATF_REQUIRE_EQ(uvm_physseg_plug(VALID_START_PFN_4, npages4, &upm4), true);
518	/* The hot plug slab should have nothing to do with the original slab */
519	pgs = uvm_physseg_get_pg(upm4, 0);
520	ATF_REQUIRE(pgs < slab || pgs > (slab + npages1
521#if VM_PHYSSEG_MAX > 2
522		+ npages2
523#endif
524		+ npages3));
525
526}
527ATF_TC(uvm_physseg_unplug);
528ATF_TC_HEAD(uvm_physseg_unplug, tc)
529{
530	atf_tc_set_md_var(tc, "descr",
531	    "Test unplug functionality.");
532}
533ATF_TC_BODY(uvm_physseg_unplug, tc)
534{
535	paddr_t pa = 0;
536
537	psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
538	psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
539	psize_t npages3 = (VALID_END_PFN_3 - VALID_START_PFN_3);
540
541	struct vm_page *slab = malloc(sizeof(struct vm_page) * (npages1 + npages2 + npages3));
542
543	uvm_physseg_t upm;
544
545	/* Boot time */
546	setup();
547
548	/* We start with zero segments */
549	ATF_REQUIRE_EQ(true, uvm_physseg_plug(atop(0), atop(ONE_MEGABYTE), NULL));
550	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
551	/* Do we have an arbitrary offset in there ? */
552	uvm_physseg_find(atop(TWOFIFTYSIX_KILO), &pa);
553	ATF_REQUIRE_EQ(pa, atop(TWOFIFTYSIX_KILO));
554	ATF_REQUIRE_EQ(0, uvmexp.npages); /* Boot time sanity */
555
556#if VM_PHYSSEG_MAX == 1
557	/*
558	 * This is the curious case at boot time, of having one
559	 * extent(9) static entry per segment, which means that a
560	 * fragmenting unplug will fail.
561	 */
562	atf_tc_expect_signal(SIGABRT, "fragmenting unplug for single segment");
563
564	/*
565	 * In order to test the fragmenting cases, please set
566	 * VM_PHYSSEG_MAX > 1
567	 */
568#endif
569	/* Now let's unplug from the middle */
570	ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(TWOFIFTYSIX_KILO), atop(FIVEONETWO_KILO)));
571	/* verify that a gap exists at TWOFIFTYSIX_KILO */
572	pa = 0; /* reset */
573	uvm_physseg_find(atop(TWOFIFTYSIX_KILO), &pa);
574	ATF_REQUIRE_EQ(pa, 0);
575
576	/* Post boot: Fake all segments and pages accounted for. */
577	uvm_page_init_fake(slab, npages1 + npages2 + npages3);
578	/* Account for the unplug */
579	ATF_CHECK_EQ(atop(FIVEONETWO_KILO), uvmexp.npages);
580
581	/* Original entry should fragment into two */
582	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
583
584	upm = uvm_physseg_find(atop(TWOFIFTYSIX_KILO + FIVEONETWO_KILO), NULL);
585
586	ATF_REQUIRE(uvm_physseg_valid_p(upm));
587
588	/* Now unplug the tail fragment - should swallow the complete entry */
589	ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(TWOFIFTYSIX_KILO + FIVEONETWO_KILO), atop(TWOFIFTYSIX_KILO)));
590
591	/* The "swallow" above should have invalidated the handle */
592	ATF_REQUIRE_EQ(false, uvm_physseg_valid_p(upm));
593
594	/* Only the first one is left now */
595	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
596
597	/* Unplug from the back */
598	ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(ONETWENTYEIGHT_KILO), atop(ONETWENTYEIGHT_KILO)));
599	/* Shouldn't change the number of segments */
600	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
601
602	/* Unplug from the front */
603	ATF_REQUIRE_EQ(true, uvm_physseg_unplug(0, atop(SIXTYFOUR_KILO)));
604	/* Shouldn't change the number of segments */
605	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
606
607	/* Unplugging the final fragment should fail */
608	atf_tc_expect_signal(SIGABRT, "Unplugging the last segment");
609	ATF_REQUIRE_EQ(true, uvm_physseg_unplug(atop(SIXTYFOUR_KILO), atop(SIXTYFOUR_KILO)));
610}
611
612
613/* <---- end Tests for Internal functions ----> */
614
615/* Tests for functions exported via uvm_physseg.h */
616ATF_TC(uvm_physseg_init);
617ATF_TC_HEAD(uvm_physseg_init, tc)
618{
619	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_init() call\
620	    initializes the vm_physmem struct which holds the rb_tree.");
621}
622ATF_TC_BODY(uvm_physseg_init, tc)
623{
624	uvm_physseg_init();
625
626	ATF_REQUIRE_EQ(0, uvm_physseg_get_entries());
627}
628
629ATF_TC(uvm_page_physload_preload);
630ATF_TC_HEAD(uvm_page_physload_preload, tc)
631{
632	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
633	    call works without a panic() in a preload scenario.");
634}
635ATF_TC_BODY(uvm_page_physload_preload, tc)
636{
637	uvm_physseg_t upm;
638
639	setup();
640
641	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
642	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
643
644	/* Should return a valid handle */
645	ATF_REQUIRE(uvm_physseg_valid_p(upm));
646
647	/* No pages should be allocated yet */
648	ATF_REQUIRE_EQ(0, uvmexp.npages);
649
650	/* After the first call one segment should exist */
651	ATF_CHECK_EQ(1, uvm_physseg_get_entries());
652
653	/* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
654#if VM_PHYSSEG_MAX > 1
655	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
656	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
657
658	/* Should return a valid handle */
659	ATF_REQUIRE(uvm_physseg_valid_p(upm));
660
661	ATF_REQUIRE_EQ(0, uvmexp.npages);
662
663	/* After the second call two segments should exist */
664	ATF_CHECK_EQ(2, uvm_physseg_get_entries());
665#endif
666}
667
668ATF_TC(uvm_page_physload_postboot);
669ATF_TC_HEAD(uvm_page_physload_postboot, tc)
670{
671	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
672	     panic()s in a post boot scenario.");
673}
674ATF_TC_BODY(uvm_page_physload_postboot, tc)
675{
676	uvm_physseg_t upm;
677
678	psize_t npages1 = (VALID_END_PFN_1 - VALID_START_PFN_1);
679	psize_t npages2 = (VALID_END_PFN_2 - VALID_START_PFN_2);
680
681	struct vm_page *slab = malloc(sizeof(struct vm_page) * (npages1 + npages2));
682
683	setup();
684
685	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
686	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
687
688	/* Should return a valid handle */
689	ATF_REQUIRE(uvm_physseg_valid_p(upm));
690
691	/* No pages should be allocated yet */
692	ATF_REQUIRE_EQ(0, uvmexp.npages);
693
694	/* After the first call one segment should exist */
695	ATF_CHECK_EQ(1, uvm_physseg_get_entries());
696
697	/* Post boot: Fake all segments and pages accounted for. */
698	uvm_page_init_fake(slab, npages1 + npages2);
699
700	atf_tc_expect_signal(SIGABRT,
701	    "uvm_page_physload() called post boot");
702
703	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
704	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
705
706	/* Should return a valid handle */
707	ATF_REQUIRE(uvm_physseg_valid_p(upm));
708
709	ATF_REQUIRE_EQ(npages1 + npages2, uvmexp.npages);
710
711	/* After the second call two segments should exist */
712	ATF_CHECK_EQ(2, uvm_physseg_get_entries());
713}
714
715ATF_TC(uvm_physseg_handle_immutable);
716ATF_TC_HEAD(uvm_physseg_handle_immutable, tc)
717{
718	atf_tc_set_md_var(tc, "descr", "Tests if the uvm_physseg_t handle is \
719	    immutable.");
720}
721ATF_TC_BODY(uvm_physseg_handle_immutable, tc)
722{
723	uvm_physseg_t upm;
724
725	/* We insert the segments in out of order */
726
727	setup();
728
729	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
730	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
731
732	ATF_REQUIRE_EQ(0, uvmexp.npages);
733
734	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
735
736	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY, uvm_physseg_get_prev(upm));
737
738	/* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
739#if VM_PHYSSEG_MAX > 1
740	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
741	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
742
743	ATF_REQUIRE_EQ(0, uvmexp.npages);
744
745	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
746
747	/* Fetch Previous, we inserted a lower value */
748	upm = uvm_physseg_get_prev(upm);
749
750#if !defined(UVM_HOTPLUG)
751	/*
752	 * This test is going to fail for the Array Implementation but is
753	 * expected to pass in the RB Tree implementation.
754	 */
755	/* Failure can be expected iff there are more than one handles */
756	atf_tc_expect_fail("Mutable handle in static array impl.");
757#endif
758	ATF_CHECK(UVM_PHYSSEG_TYPE_INVALID_EMPTY != upm);
759	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
760	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
761#endif
762}
763
764ATF_TC(uvm_physseg_seg_chomp_slab);
765ATF_TC_HEAD(uvm_physseg_seg_chomp_slab, tc)
766{
767	atf_tc_set_md_var(tc, "descr", "The slab import code.()");
768
769}
770ATF_TC_BODY(uvm_physseg_seg_chomp_slab, tc)
771{
772	int err;
773	size_t i;
774	struct uvm_physseg *seg;
775	struct vm_page *slab, *pgs;
776	const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
777
778	setup();
779
780	/* This is boot time */
781	slab = malloc(sizeof(struct vm_page) * npages * 2);
782
783	seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
784
785	uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
786
787	/* Should be able to allocate two 128 * sizeof(*slab) */
788	ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
789	err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
790
791#if VM_PHYSSEG_MAX == 1
792	/*
793	 * free() needs an extra region descriptor, but we only have
794	 * one! The classic alloc() at free() problem
795	 */
796
797	ATF_REQUIRE_EQ(ENOMEM, err);
798#else
799	/* Try alloc/free at static time */
800	for (i = 0; i < npages; i++) {
801		ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
802		err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
803		ATF_REQUIRE_EQ(0, err);
804	}
805#endif
806
807	/* Now setup post boot */
808	uvm.page_init_done = true;
809
810	uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
811
812	/* Try alloc/free after uvm_page.c:uvm_page_init() as well */
813	for (i = 0; i < npages; i++) {
814		ATF_REQUIRE_EQ(0, extent_alloc(seg->ext, sizeof(*slab), 1, 0, EX_BOUNDZERO, (void *)&pgs));
815		err = extent_free(seg->ext, (u_long) pgs, sizeof(*slab), EX_BOUNDZERO);
816		ATF_REQUIRE_EQ(0, err);
817	}
818
819}
820
821ATF_TC(uvm_physseg_alloc_from_slab);
822ATF_TC_HEAD(uvm_physseg_alloc_from_slab, tc)
823{
824	atf_tc_set_md_var(tc, "descr", "The slab alloc code.()");
825
826}
827ATF_TC_BODY(uvm_physseg_alloc_from_slab, tc)
828{
829	struct uvm_physseg *seg;
830	struct vm_page *slab, *pgs;
831	const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
832
833	setup();
834
835	/* This is boot time */
836	slab = malloc(sizeof(struct vm_page) * npages * 2);
837
838	seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
839
840	uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
841
842	pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
843
844	ATF_REQUIRE(pgs != NULL);
845
846	/* Now setup post boot */
847	uvm.page_init_done = true;
848
849#if VM_PHYSSEG_MAX > 1
850	pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
851	ATF_REQUIRE(pgs != NULL);
852#endif
853	atf_tc_expect_fail("alloc beyond extent");
854
855	pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
856	ATF_REQUIRE(pgs != NULL);
857}
858
859ATF_TC(uvm_physseg_init_seg);
860ATF_TC_HEAD(uvm_physseg_init_seg, tc)
861{
862	atf_tc_set_md_var(tc, "descr", "Tests if uvm_physseg_init_seg adds pages to"
863	    "uvmexp.npages");
864}
865ATF_TC_BODY(uvm_physseg_init_seg, tc)
866{
867	struct uvm_physseg *seg;
868	struct vm_page *slab, *pgs;
869	const size_t npages = UVM_PHYSSEG_BOOT_UNPLUG_MAX; /* Number of pages */
870
871	setup();
872
873	/* This is boot time */
874	slab = malloc(sizeof(struct vm_page) * npages * 2);
875
876	seg = uvm_physseg_alloc(sizeof(struct uvm_physseg));
877
878	uvm_physseg_seg_chomp_slab(PHYSSEG_NODE_TO_HANDLE(seg), slab, npages * 2);
879
880	pgs = uvm_physseg_seg_alloc_from_slab(PHYSSEG_NODE_TO_HANDLE(seg), npages);
881
882	ATF_REQUIRE_EQ(0, uvmexp.npages);
883
884	seg->start = 0;
885	seg->end = npages;
886
887	seg->avail_start = 0;
888	seg->avail_end = npages;
889
890	uvm_physseg_init_seg(PHYSSEG_NODE_TO_HANDLE(seg), pgs);
891
892	ATF_REQUIRE_EQ(npages, uvmexp.npages);
893}
894
895#if 0
896ATF_TC(uvm_physseg_init_seg);
897ATF_TC_HEAD(uvm_physseg_init_seg, tc)
898{
899	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physload() \
900	    call works without a panic() after Segment is inited.");
901}
902ATF_TC_BODY(uvm_physseg_init_seg, tc)
903{
904	uvm_physseg_t upm;
905	psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
906	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
907
908	setup();
909	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
910	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
911
912	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
913
914	ATF_CHECK_EQ(0, uvmexp.npages);
915
916	/*
917	 * Boot time physplug needs explicit external init,
918	 * Duplicate what uvm_page.c:uvm_page_init() does.
919	 * Note: not everything uvm_page_init() does gets done here.
920	 * Read the source.
921	 */
922	/* suck in backing slab, initialise extent. */
923	uvm_physseg_seg_chomp_slab(upm, pgs, npages);
924
925	/*
926	 * Actual pgs[] allocation, from extent.
927	 */
928	uvm_physseg_alloc_from_slab(upm, npages);
929
930	/* Now we initialize the segment */
931	uvm_physseg_init_seg(upm, pgs);
932
933	/* Done with boot simulation */
934	extent_init();
935	uvm.page_init_done = true;
936
937	/* We have total memory of 1MB */
938	ATF_CHECK_EQ(PAGE_COUNT_1M, uvmexp.npages);
939
940	upm =uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
941	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
942	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
943
944	/* We added another 1MB so PAGE_COUNT_1M + PAGE_COUNT_1M */
945	ATF_CHECK_EQ(PAGE_COUNT_1M + PAGE_COUNT_1M, uvmexp.npages);
946
947}
948#endif
949
950ATF_TC(uvm_physseg_get_start);
951ATF_TC_HEAD(uvm_physseg_get_start, tc)
952{
953	atf_tc_set_md_var(tc, "descr", "Tests if the start PFN is returned \
954	    correctly from a segment created via uvm_page_physload().");
955}
956ATF_TC_BODY(uvm_physseg_get_start, tc)
957{
958	uvm_physseg_t upm;
959
960	/* Fake early boot */
961	setup();
962
963	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
964	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
965
966	ATF_REQUIRE_EQ(0, uvmexp.npages);
967
968	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
969
970	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
971
972	/* This test will be triggered only if there are 2 or more segments. */
973#if VM_PHYSSEG_MAX > 1
974	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
975	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
976
977	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
978
979	ATF_REQUIRE_EQ(0, uvmexp.npages);
980
981	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
982#endif
983}
984
985ATF_TC(uvm_physseg_get_start_invalid);
986ATF_TC_HEAD(uvm_physseg_get_start_invalid, tc)
987{
988	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
989	    correctly when uvm_physseg_get_start() is called with invalid \
990	    parameter values.");
991}
992ATF_TC_BODY(uvm_physseg_get_start_invalid, tc)
993{
994	/* Check for pgs == NULL */
995	setup();
996	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
997	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
998
999	/* Force other check conditions */
1000	uvm.page_init_done = true;
1001
1002	ATF_REQUIRE_EQ(0, uvmexp.npages);
1003
1004	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1005
1006	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1007
1008	/* Invalid uvm_physseg_t */
1009	ATF_CHECK_EQ((paddr_t) -1,
1010	    uvm_physseg_get_start(UVM_PHYSSEG_TYPE_INVALID));
1011}
1012
1013ATF_TC(uvm_physseg_get_end);
1014ATF_TC_HEAD(uvm_physseg_get_end, tc)
1015{
1016	atf_tc_set_md_var(tc, "descr", "Tests if the end PFN is returned \
1017	    correctly from a segment created via uvm_page_physload().");
1018}
1019ATF_TC_BODY(uvm_physseg_get_end, tc)
1020{
1021	uvm_physseg_t upm;
1022
1023	setup();
1024	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1025	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1026
1027	ATF_REQUIRE_EQ(0, uvmexp.npages);
1028
1029	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1030
1031	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
1032
1033	/* This test will be triggered only if there are 2 or more segments. */
1034#if VM_PHYSSEG_MAX > 1
1035	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1036	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1037
1038	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1039
1040	ATF_REQUIRE_EQ(0, uvmexp.npages);
1041
1042	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
1043#endif
1044}
1045
1046ATF_TC(uvm_physseg_get_end_invalid);
1047ATF_TC_HEAD(uvm_physseg_get_end_invalid, tc)
1048{
1049	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
1050	    correctly when uvm_physseg_get_end() is called with invalid \
1051	    parameter values.");
1052}
1053ATF_TC_BODY(uvm_physseg_get_end_invalid, tc)
1054{
1055	/* Check for pgs == NULL */
1056	setup();
1057	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1058	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1059
1060	/* Force other check conditions */
1061	uvm.page_init_done = true;
1062
1063	ATF_REQUIRE_EQ(0, uvmexp.npages);
1064
1065	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1066
1067	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1068
1069	/* Invalid uvm_physseg_t */
1070	ATF_CHECK_EQ((paddr_t) -1,
1071	    uvm_physseg_get_end(UVM_PHYSSEG_TYPE_INVALID));
1072}
1073
1074ATF_TC(uvm_physseg_get_avail_start);
1075ATF_TC_HEAD(uvm_physseg_get_avail_start, tc)
1076{
1077	atf_tc_set_md_var(tc, "descr", "Tests if the avail_start PFN is \
1078	    returned correctly from a segment created via uvm_page_physload().");
1079}
1080ATF_TC_BODY(uvm_physseg_get_avail_start, tc)
1081{
1082	uvm_physseg_t upm;
1083
1084	setup();
1085	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1086	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1087
1088	ATF_REQUIRE_EQ(0, uvmexp.npages);
1089
1090	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1091
1092	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
1093
1094	/* This test will be triggered only if there are 2 or more segments. */
1095#if VM_PHYSSEG_MAX > 1
1096	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1097	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1098
1099	ATF_REQUIRE_EQ(0, uvmexp.npages);
1100
1101	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1102
1103	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
1104#endif
1105}
1106
1107ATF_TC(uvm_physseg_get_avail_start_invalid);
1108ATF_TC_HEAD(uvm_physseg_get_avail_start_invalid, tc)
1109{
1110	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
1111	    correctly when uvm_physseg_get_avail_start() is called with invalid\
1112	    parameter values.");
1113}
1114ATF_TC_BODY(uvm_physseg_get_avail_start_invalid, tc)
1115{
1116	/* Check for pgs == NULL */
1117	setup();
1118	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1119	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1120
1121	/* Force other check conditions */
1122	uvm.page_init_done = true;
1123
1124	ATF_REQUIRE_EQ(0, uvmexp.npages);
1125
1126	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1127
1128	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1129
1130	/* Invalid uvm_physseg_t */
1131	ATF_CHECK_EQ((paddr_t) -1,
1132	    uvm_physseg_get_avail_start(UVM_PHYSSEG_TYPE_INVALID));
1133}
1134
1135ATF_TC(uvm_physseg_get_avail_end);
1136ATF_TC_HEAD(uvm_physseg_get_avail_end, tc)
1137{
1138	atf_tc_set_md_var(tc, "descr", "Tests if the avail_end PFN is \
1139	    returned correctly from a segment created via uvm_page_physload().");
1140}
1141ATF_TC_BODY(uvm_physseg_get_avail_end, tc)
1142{
1143	uvm_physseg_t upm;
1144
1145	setup();
1146	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1147	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1148
1149	ATF_REQUIRE_EQ(0, uvmexp.npages);
1150
1151	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1152
1153	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
1154
1155	/* This test will be triggered only if there are 2 or more segments. */
1156#if VM_PHYSSEG_MAX > 1
1157	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1158	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1159
1160	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1161
1162	ATF_REQUIRE_EQ(0, uvmexp.npages);
1163
1164	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
1165#endif
1166}
1167
1168ATF_TC(uvm_physseg_get_avail_end_invalid);
1169ATF_TC_HEAD(uvm_physseg_get_avail_end_invalid, tc)
1170{
1171	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
1172	    correctly when uvm_physseg_get_avail_end() is called with invalid\
1173	    parameter values.");
1174}
1175ATF_TC_BODY(uvm_physseg_get_avail_end_invalid, tc)
1176{
1177	/* Check for pgs == NULL */
1178	setup();
1179	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1180	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1181
1182	/* Force other check conditions */
1183	uvm.page_init_done = true;
1184
1185	ATF_REQUIRE_EQ(0, uvmexp.npages);
1186
1187	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1188
1189	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1190
1191	/* Invalid uvm_physseg_t */
1192	ATF_CHECK_EQ((paddr_t) -1,
1193	    uvm_physseg_get_avail_end(UVM_PHYSSEG_TYPE_INVALID));
1194}
1195
1196ATF_TC(uvm_physseg_get_next);
1197ATF_TC_HEAD(uvm_physseg_get_next, tc)
1198{
1199	atf_tc_set_md_var(tc, "descr", "Tests the pointer values for next \
1200	    segment using the uvm_physseg_get_next() call.");
1201}
1202ATF_TC_BODY(uvm_physseg_get_next, tc)
1203{
1204	uvm_physseg_t upm;
1205#if VM_PHYSSEG_MAX > 1
1206	uvm_physseg_t upm_next;
1207#endif
1208
1209	/* We insert the segments in ascending order */
1210
1211	setup();
1212	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1213	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1214
1215	ATF_REQUIRE_EQ(0, uvmexp.npages);
1216
1217	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1218
1219	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_OVERFLOW,
1220	    uvm_physseg_get_next(upm));
1221
1222	/* This test will be triggered only if there are 2 or more segments. */
1223#if VM_PHYSSEG_MAX > 1
1224	upm_next = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1225	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1226
1227	ATF_REQUIRE_EQ(0, uvmexp.npages);
1228
1229	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1230
1231	upm = uvm_physseg_get_next(upm); /* Fetch Next */
1232
1233	ATF_CHECK_EQ(upm_next, upm);
1234	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
1235	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
1236#endif
1237
1238	/* This test will be triggered only if there are 3 or more segments. */
1239#if VM_PHYSSEG_MAX > 2
1240	upm_next = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1241	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
1242
1243	ATF_REQUIRE_EQ(0, uvmexp.npages);
1244
1245	ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
1246
1247	upm = uvm_physseg_get_next(upm); /* Fetch Next */
1248
1249	ATF_CHECK_EQ(upm_next, upm);
1250	ATF_CHECK_EQ(VALID_START_PFN_3, uvm_physseg_get_start(upm));
1251	ATF_CHECK_EQ(VALID_END_PFN_3, uvm_physseg_get_end(upm));
1252#endif
1253}
1254
1255ATF_TC(uvm_physseg_get_next_invalid);
1256ATF_TC_HEAD(uvm_physseg_get_next_invalid, tc)
1257{
1258	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
1259	    correctly when uvm_physseg_get_next() is called with invalid \
1260	    parameter values.");
1261}
1262ATF_TC_BODY(uvm_physseg_get_next_invalid, tc)
1263{
1264	uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID;
1265
1266	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID, uvm_physseg_get_next(upm));
1267}
1268
1269ATF_TC(uvm_physseg_get_prev);
1270ATF_TC_HEAD(uvm_physseg_get_prev, tc)
1271{
1272	atf_tc_set_md_var(tc, "descr", "Tests the pointer values for previous \
1273	    segment using the uvm_physseg_get_prev() call.");
1274}
1275ATF_TC_BODY(uvm_physseg_get_prev, tc)
1276{
1277#if VM_PHYSSEG_MAX > 1
1278	uvm_physseg_t upm;
1279#endif
1280	uvm_physseg_t upm_prev;
1281
1282
1283	setup();
1284	upm_prev = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1285	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1286
1287	ATF_REQUIRE_EQ(0, uvmexp.npages);
1288
1289	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1290
1291	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY,
1292	    uvm_physseg_get_prev(upm_prev));
1293
1294	/* This test will be triggered only if there are 2 or more segments. */
1295#if VM_PHYSSEG_MAX > 1
1296	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1297	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1298
1299	ATF_REQUIRE_EQ(0, uvmexp.npages);
1300
1301	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1302
1303	/* Fetch Previous, we inserted a lower value */
1304	upm = uvm_physseg_get_prev(upm);
1305
1306	ATF_CHECK_EQ(upm_prev, upm);
1307	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
1308	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
1309#endif
1310
1311	/* This test will be triggered only if there are 3 or more segments. */
1312#if VM_PHYSSEG_MAX > 2
1313	uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1314	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
1315
1316	ATF_REQUIRE_EQ(0, uvmexp.npages);
1317
1318	ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
1319
1320	/*
1321	 * This will return a UVM_PHYSSEG_TYPE_INVALID_EMPTY we are at the
1322	 * lowest
1323	 */
1324	upm = uvm_physseg_get_prev(upm);
1325
1326	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID_EMPTY, upm);
1327#endif
1328}
1329
1330ATF_TC(uvm_physseg_get_prev_invalid);
1331ATF_TC_HEAD(uvm_physseg_get_prev_invalid, tc)
1332{
1333	atf_tc_set_md_var(tc, "descr", "Tests the invalid / error conditions \
1334	    correctly when uvm_physseg_get_prev() is called with invalid \
1335	    parameter values.");
1336}
1337ATF_TC_BODY(uvm_physseg_get_prev_invalid, tc)
1338{
1339	uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID;
1340
1341	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID, uvm_physseg_get_prev(upm));
1342}
1343
1344ATF_TC(uvm_physseg_get_first);
1345ATF_TC_HEAD(uvm_physseg_get_first, tc)
1346{
1347	atf_tc_set_md_var(tc, "descr", "Tests the pointer values for first \
1348	    segment (lowest node) using the uvm_physseg_get_first() call.");
1349}
1350ATF_TC_BODY(uvm_physseg_get_first, tc)
1351{
1352	uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID_EMPTY;
1353	uvm_physseg_t upm_first;
1354
1355	/* Fake early boot */
1356	setup();
1357
1358	/* No nodes exist */
1359	ATF_CHECK_EQ(upm, uvm_physseg_get_first());
1360
1361	upm_first = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1362	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1363
1364	ATF_REQUIRE_EQ(0, uvmexp.npages);
1365
1366	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1367
1368	/* Pointer to first should be the least valued node */
1369	upm = uvm_physseg_get_first();
1370	ATF_CHECK_EQ(upm_first, upm);
1371	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
1372	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
1373	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
1374	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
1375
1376	/* This test will be triggered only if there are 2 or more segments. */
1377#if VM_PHYSSEG_MAX > 1
1378	/* Insert a node of lesser value */
1379	upm_first = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1380	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1381
1382	ATF_CHECK_EQ(0, uvmexp.npages);
1383
1384	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1385
1386	/* Pointer to first should be the least valued node */
1387	upm = uvm_physseg_get_first();
1388	ATF_CHECK_EQ(upm_first, upm);
1389	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
1390	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
1391	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
1392	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
1393#endif
1394
1395	/* This test will be triggered only if there are 3 or more segments. */
1396#if VM_PHYSSEG_MAX > 2
1397	/* Insert a node of higher value */
1398	upm_first =uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1399	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
1400
1401	ATF_CHECK_EQ(0, uvmexp.npages);
1402
1403	ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
1404
1405	/* Pointer to first should be the least valued node */
1406	upm = uvm_physseg_get_first();
1407	ATF_CHECK(upm_first != upm);
1408	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
1409	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
1410	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
1411	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
1412#endif
1413}
1414
1415ATF_TC(uvm_physseg_get_last);
1416ATF_TC_HEAD(uvm_physseg_get_last, tc)
1417{
1418	atf_tc_set_md_var(tc, "descr", "Tests the pointer values for last \
1419	    segment using the uvm_physseg_get_last() call.");
1420}
1421ATF_TC_BODY(uvm_physseg_get_last, tc)
1422{
1423	uvm_physseg_t upm = UVM_PHYSSEG_TYPE_INVALID_EMPTY;
1424	uvm_physseg_t upm_last;
1425
1426	setup();
1427
1428	/* No nodes exist */
1429	ATF_CHECK_EQ(upm, uvm_physseg_get_last());
1430
1431	upm_last = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1432	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1433
1434	ATF_REQUIRE_EQ(0, uvmexp.npages);
1435
1436	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1437
1438	/* Pointer to last should be the most valued node */
1439	upm = uvm_physseg_get_last();
1440	ATF_CHECK_EQ(upm_last, upm);
1441	ATF_CHECK_EQ(VALID_START_PFN_1, uvm_physseg_get_start(upm));
1442	ATF_CHECK_EQ(VALID_END_PFN_1, uvm_physseg_get_end(upm));
1443	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_1, uvm_physseg_get_avail_start(upm));
1444	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1, uvm_physseg_get_avail_end(upm));
1445
1446	/* This test will be triggered only if there are 2 or more segments. */
1447#if VM_PHYSSEG_MAX > 1
1448	/* Insert node of greater value */
1449	upm_last = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1450	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1451
1452	ATF_REQUIRE_EQ(0, uvmexp.npages);
1453
1454	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1455
1456	/* Pointer to last should be the most valued node */
1457	upm = uvm_physseg_get_last();
1458	ATF_CHECK_EQ(upm_last, upm);
1459	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
1460	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
1461	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
1462	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
1463#endif
1464
1465	/* This test will be triggered only if there are 3 or more segments. */
1466#if VM_PHYSSEG_MAX > 2
1467	/* Insert node of greater value */
1468	upm_last = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1469	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
1470
1471	ATF_REQUIRE_EQ(0, uvmexp.npages);
1472
1473	ATF_REQUIRE_EQ(3, uvm_physseg_get_entries());
1474
1475	/* Pointer to last should be the most valued node */
1476	upm = uvm_physseg_get_last();
1477	ATF_CHECK_EQ(upm_last, upm);
1478	ATF_CHECK_EQ(VALID_START_PFN_3, uvm_physseg_get_start(upm));
1479	ATF_CHECK_EQ(VALID_END_PFN_3, uvm_physseg_get_end(upm));
1480	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_3, uvm_physseg_get_avail_start(upm));
1481	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3, uvm_physseg_get_avail_end(upm));
1482#endif
1483}
1484
1485ATF_TC(uvm_physseg_valid);
1486ATF_TC_HEAD(uvm_physseg_valid, tc)
1487{
1488	atf_tc_set_md_var(tc, "descr", "Tests the pointer value for current \
1489	    segment is valid using the uvm_physseg_valid_p() call.");
1490}
1491ATF_TC_BODY(uvm_physseg_valid, tc)
1492{
1493	psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
1494
1495	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
1496
1497	uvm_physseg_t upm;
1498
1499	setup();
1500	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1501	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1502
1503	ATF_REQUIRE_EQ(0, uvmexp.npages);
1504
1505	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1506
1507	uvm_physseg_init_seg(upm, pgs);
1508
1509	ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
1510
1511	ATF_CHECK_EQ(true, uvm_physseg_valid_p(upm));
1512}
1513
1514ATF_TC(uvm_physseg_valid_invalid);
1515ATF_TC_HEAD(uvm_physseg_valid_invalid, tc)
1516{
1517	atf_tc_set_md_var(tc, "descr", "Tests the pointer value for current \
1518	    segment is invalid using the uvm_physseg_valid_p() call.");
1519}
1520ATF_TC_BODY(uvm_physseg_valid_invalid, tc)
1521{
1522	uvm_physseg_t upm;
1523
1524	setup();
1525	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1526	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1527
1528	/* Force other check conditions */
1529	uvm.page_init_done = true;
1530
1531	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1532
1533	/* Invalid uvm_physseg_t */
1534	ATF_CHECK_EQ(false, uvm_physseg_valid_p(UVM_PHYSSEG_TYPE_INVALID));
1535
1536	/*
1537	 * Without any pages initialized for segment, it is considered
1538	 * invalid
1539	 */
1540	ATF_CHECK_EQ(false, uvm_physseg_valid_p(upm));
1541}
1542
1543ATF_TC(uvm_physseg_get_highest);
1544ATF_TC_HEAD(uvm_physseg_get_highest, tc)
1545{
1546	atf_tc_set_md_var(tc, "descr", "Tests if the returned PFN matches  \
1547	    the highest PFN in use by the system.");
1548}
1549ATF_TC_BODY(uvm_physseg_get_highest, tc)
1550{
1551	setup();
1552	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1553	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1554
1555	/* Only one segment so highest is the current */
1556	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_1 - 1, uvm_physseg_get_highest_frame());
1557
1558	/* This test will be triggered only if there are 2 or more segments. */
1559#if VM_PHYSSEG_MAX > 1
1560	uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1561	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_DEFAULT);
1562
1563	/* PFN_3 > PFN_1 */
1564	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3 - 1, uvm_physseg_get_highest_frame());
1565#endif
1566
1567	/* This test will be triggered only if there are 3 or more segments. */
1568#if VM_PHYSSEG_MAX > 2
1569	uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1570	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1571
1572	/* PFN_3 > PFN_2 */
1573	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_3 - 1, uvm_physseg_get_highest_frame());
1574#endif
1575}
1576
1577ATF_TC(uvm_physseg_get_free_list);
1578ATF_TC_HEAD(uvm_physseg_get_free_list, tc)
1579{
1580	atf_tc_set_md_var(tc, "descr", "Tests if the returned Free List type \
1581	    of a segment matches the one returned from \
1582	    uvm_physseg_get_free_list() call.");
1583}
1584ATF_TC_BODY(uvm_physseg_get_free_list, tc)
1585{
1586	uvm_physseg_t upm;
1587
1588	/* Fake early boot */
1589	setup();
1590
1591	/* Insertions are made in ascending order */
1592	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1593	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1594
1595	ATF_CHECK_EQ(VM_FREELIST_DEFAULT, uvm_physseg_get_free_list(upm));
1596
1597	/* This test will be triggered only if there are 2 or more segments. */
1598#if VM_PHYSSEG_MAX > 1
1599	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1600	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_FIRST16);
1601
1602	ATF_CHECK_EQ(VM_FREELIST_FIRST16, uvm_physseg_get_free_list(upm));
1603#endif
1604
1605	/* This test will be triggered only if there are 3 or more segments. */
1606#if VM_PHYSSEG_MAX > 2
1607	upm = uvm_page_physload(VALID_START_PFN_3, VALID_END_PFN_3,
1608	    VALID_AVAIL_START_PFN_3, VALID_AVAIL_END_PFN_3, VM_FREELIST_FIRST1G);
1609
1610	ATF_CHECK_EQ(VM_FREELIST_FIRST1G, uvm_physseg_get_free_list(upm));
1611#endif
1612}
1613
1614ATF_TC(uvm_physseg_get_start_hint);
1615ATF_TC_HEAD(uvm_physseg_get_start_hint, tc)
1616{
1617	atf_tc_set_md_var(tc, "descr", "Tests if the returned start_hint value \
1618	    of a segment matches the one returned from \
1619	    uvm_physseg_get_start_hint() call.");
1620}
1621ATF_TC_BODY(uvm_physseg_get_start_hint, tc)
1622{
1623	uvm_physseg_t upm;
1624
1625	setup();
1626	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1627	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1628
1629	/* Will be Zero since no specific value is set during init */
1630	ATF_CHECK_EQ(0, uvm_physseg_get_start_hint(upm));
1631}
1632
1633ATF_TC(uvm_physseg_set_start_hint);
1634ATF_TC_HEAD(uvm_physseg_set_start_hint, tc)
1635{
1636	atf_tc_set_md_var(tc, "descr", "Tests if the returned start_hint value \
1637	    of a segment matches the one set by the \
1638	    uvm_physseg_set_start_hint() call.");
1639}
1640ATF_TC_BODY(uvm_physseg_set_start_hint, tc)
1641{
1642	psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
1643
1644	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
1645
1646	uvm_physseg_t upm;
1647
1648	setup();
1649	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1650	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1651
1652	uvm_physseg_init_seg(upm, pgs);
1653
1654	ATF_CHECK_EQ(true, uvm_physseg_set_start_hint(upm, atop(128)));
1655
1656	/* Will be atop(128) since no specific value is set above */
1657	ATF_CHECK_EQ(atop(128), uvm_physseg_get_start_hint(upm));
1658}
1659
1660ATF_TC(uvm_physseg_set_start_hint_invalid);
1661ATF_TC_HEAD(uvm_physseg_set_start_hint_invalid, tc)
1662{
1663	atf_tc_set_md_var(tc, "descr", "Tests if the returned value is false \
1664	    when an invalid segment matches the one trying to set by the \
1665	    uvm_physseg_set_start_hint() call.");
1666}
1667ATF_TC_BODY(uvm_physseg_set_start_hint_invalid, tc)
1668{
1669	uvm_physseg_t upm;
1670
1671	setup();
1672	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1673	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1674
1675	/* Force other check conditions */
1676	uvm.page_init_done = true;
1677
1678	ATF_REQUIRE_EQ(true, uvm.page_init_done);
1679
1680	ATF_CHECK_EQ(false, uvm_physseg_set_start_hint(upm, atop(128)));
1681
1682	/*
1683	 * Will be Zero since no specific value is set after the init
1684	 * due to failure
1685	 */
1686	atf_tc_expect_signal(SIGABRT, "invalid uvm_physseg_t handle");
1687
1688	ATF_CHECK_EQ(0, uvm_physseg_get_start_hint(upm));
1689}
1690
1691ATF_TC(uvm_physseg_get_pg);
1692ATF_TC_HEAD(uvm_physseg_get_pg, tc)
1693{
1694	atf_tc_set_md_var(tc, "descr", "Tests if the returned vm_page struct \
1695	    is correct when fetched by uvm_physseg_get_pg() call.");
1696}
1697ATF_TC_BODY(uvm_physseg_get_pg, tc)
1698{
1699	psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
1700
1701	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
1702
1703	struct vm_page *extracted_pg = NULL;
1704
1705	uvm_physseg_t upm;
1706
1707	setup();
1708	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1709	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1710
1711	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1712
1713	ATF_REQUIRE_EQ(0, uvmexp.npages);
1714
1715	/* Now we initialize the segment */
1716	uvm_physseg_init_seg(upm, pgs);
1717
1718	ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
1719
1720	ATF_REQUIRE_EQ(NULL, extracted_pg);
1721
1722	/* Try fetching the 5th Page in the Segment */
1723	extracted_pg = uvm_physseg_get_pg(upm, 5);
1724
1725	/* Values of phys_addr is n * PAGE_SIZE where n is the page number */
1726	ATF_CHECK_EQ(5 * PAGE_SIZE, extracted_pg->phys_addr);
1727
1728	/* Try fetching the 113th Page in the Segment */
1729	extracted_pg = uvm_physseg_get_pg(upm, 113);
1730
1731	ATF_CHECK_EQ(113 * PAGE_SIZE, extracted_pg->phys_addr);
1732}
1733
1734#ifdef __HAVE_PMAP_PHYSSEG
1735ATF_TC(uvm_physseg_get_pmseg);
1736ATF_TC_HEAD(uvm_physseg_get_pmseg, tc)
1737{
1738	atf_tc_set_md_var(tc, "descr", "Tests if the returned pmap_physseg \
1739	    struct is correct when fetched by uvm_physseg_get_pmseg() call.");
1740}
1741ATF_TC_BODY(uvm_physseg_get_pmseg, tc)
1742{
1743	psize_t npages = (VALID_END_PFN_1 - VALID_START_PFN_1);
1744
1745	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
1746
1747	struct pmap_physseg pmseg = { true };
1748
1749	struct pmap_physseg *extracted_pmseg = NULL;
1750
1751	uvm_physseg_t upm;
1752
1753	setup();
1754	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1755	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1756
1757	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1758
1759	ATF_REQUIRE_EQ(0, uvmexp.npages);
1760
1761	/* Now we initialize the segment */
1762	uvm_physseg_init_seg(upm, pgs);
1763
1764	ATF_REQUIRE_EQ(PAGE_COUNT_1M, uvmexp.npages);
1765
1766	ATF_REQUIRE_EQ(NULL, extracted_pmseg);
1767
1768	ATF_REQUIRE_EQ(true, pmseg.dummy_variable);
1769
1770	/* Extract the current pmseg */
1771	extracted_pmseg = uvm_physseg_get_pmseg(upm);
1772
1773	/*
1774	 * We can only check if it is not NULL
1775	 * We do not know the value it contains
1776	 */
1777	ATF_CHECK(NULL != extracted_pmseg);
1778
1779	extracted_pmseg->dummy_variable = pmseg.dummy_variable;
1780
1781	/* Invert value to ensure test integrity */
1782	pmseg.dummy_variable = false;
1783
1784	ATF_REQUIRE_EQ(false, pmseg.dummy_variable);
1785
1786	extracted_pmseg = uvm_physseg_get_pmseg(upm);
1787
1788	ATF_CHECK(NULL != extracted_pmseg);
1789
1790	ATF_CHECK_EQ(true, extracted_pmseg->dummy_variable);
1791}
1792#endif
1793
1794ATF_TC(vm_physseg_find);
1795ATF_TC_HEAD(vm_physseg_find, tc)
1796{
1797	atf_tc_set_md_var(tc, "descr", "Tests if the returned segment number \
1798	    is correct when an PFN is passed into uvm_physseg_find() call. \
1799	    In addition	to this the offset of the PFN from the start of \
1800	    segment is also set if the parameter is passed in as not NULL.");
1801}
1802ATF_TC_BODY(vm_physseg_find, tc)
1803{
1804	psize_t offset = (psize_t) -1;
1805
1806	uvm_physseg_t upm_first, result;
1807#if VM_PHYSSEG_MAX > 1
1808	uvm_physseg_t upm_second;
1809#endif
1810
1811	setup();
1812
1813	upm_first = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1814	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1815
1816	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1817
1818	ATF_REQUIRE_EQ(0, uvmexp.npages);
1819
1820	/* This test will be triggered only if there are 2 or more segments. */
1821#if VM_PHYSSEG_MAX > 1
1822	upm_second = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1823	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1824
1825	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
1826
1827	ATF_REQUIRE_EQ(0, uvmexp.npages);
1828#endif
1829
1830	/* Under ONE_MEGABYTE is segment upm_first */
1831	result = uvm_physseg_find(atop(ONE_MEGABYTE - 1024), NULL);
1832	ATF_CHECK_EQ(upm_first, result);
1833	ATF_CHECK_EQ(uvm_physseg_get_start(upm_first),
1834	    uvm_physseg_get_start(result));
1835	ATF_CHECK_EQ(uvm_physseg_get_end(upm_first),
1836	    uvm_physseg_get_end(result));
1837	ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_first),
1838	    uvm_physseg_get_avail_start(result));
1839	ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_first),
1840	    uvm_physseg_get_avail_end(result));
1841
1842	ATF_REQUIRE_EQ((psize_t) -1, offset);
1843
1844	/* This test will be triggered only if there are 2 or more segments. */
1845#if VM_PHYSSEG_MAX > 1
1846	/* Over ONE_MEGABYTE is segment upm_second */
1847	result = uvm_physseg_find(atop(ONE_MEGABYTE + 8192), &offset);
1848	ATF_CHECK_EQ(upm_second, result);
1849	ATF_CHECK_EQ(uvm_physseg_get_start(upm_second),
1850	    uvm_physseg_get_start(result));
1851	ATF_CHECK_EQ(uvm_physseg_get_end(upm_second),
1852	    uvm_physseg_get_end(result));
1853	ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_second),
1854	    uvm_physseg_get_avail_start(result));
1855	ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_second),
1856	    uvm_physseg_get_avail_end(result));
1857
1858	/* Offset is calculated based on PAGE_SIZE */
1859	/* atop(ONE_MEGABYTE + (2 * PAGE_SIZE)) - VALID_START_PFN1  = 2 */
1860	ATF_CHECK_EQ(2, offset);
1861#else
1862	/* Under ONE_MEGABYTE is segment upm_first */
1863	result = uvm_physseg_find(atop(ONE_MEGABYTE - 12288), &offset);
1864	ATF_CHECK_EQ(upm_first, result);
1865	ATF_CHECK_EQ(uvm_physseg_get_start(upm_first),
1866	    uvm_physseg_get_start(result));
1867	ATF_CHECK_EQ(uvm_physseg_get_end(upm_first),
1868	    uvm_physseg_get_end(result));
1869	ATF_CHECK_EQ(uvm_physseg_get_avail_start(upm_first),
1870	    uvm_physseg_get_avail_start(result));
1871	ATF_CHECK_EQ(uvm_physseg_get_avail_end(upm_first),
1872	    uvm_physseg_get_avail_end(result));
1873
1874	/* Offset is calculated based on PAGE_SIZE */
1875	/* atop(ONE_MEGABYTE - (3 * PAGE_SIZE)) - VALID_START_PFN1  = 253 */
1876	ATF_CHECK_EQ(253, offset);
1877#endif
1878}
1879
1880ATF_TC(vm_physseg_find_invalid);
1881ATF_TC_HEAD(vm_physseg_find_invalid, tc)
1882{
1883	atf_tc_set_md_var(tc, "descr", "Tests if the returned segment number \
1884	    is (paddr_t) -1  when a non existant PFN is passed into \
1885	    uvm_physseg_find() call.");
1886}
1887ATF_TC_BODY(vm_physseg_find_invalid, tc)
1888{
1889	psize_t offset = (psize_t) -1;
1890
1891	setup();
1892	uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
1893	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
1894
1895	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1896
1897	ATF_REQUIRE_EQ(0, uvmexp.npages);
1898
1899	/* No segments over 3 MB exists at the moment */
1900	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID,
1901	    uvm_physseg_find(atop(ONE_MEGABYTE * 3), NULL));
1902
1903	ATF_REQUIRE_EQ((psize_t) -1, offset);
1904
1905	/* No segments over 3 MB exists at the moment */
1906	ATF_CHECK_EQ(UVM_PHYSSEG_TYPE_INVALID,
1907	    uvm_physseg_find(atop(ONE_MEGABYTE * 3), &offset));
1908
1909	ATF_CHECK_EQ((psize_t) -1, offset);
1910}
1911
1912ATF_TC(uvm_page_physunload_start);
1913ATF_TC_HEAD(uvm_page_physunload_start, tc)
1914{
1915	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
1916	    call works without a panic(). Unloads from Start of the segment.");
1917}
1918ATF_TC_BODY(uvm_page_physunload_start, tc)
1919{
1920	/*
1921	 * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
1922	 */
1923	psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
1924
1925	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
1926
1927	paddr_t p = 0;
1928
1929	uvm_physseg_t upm;
1930
1931	setup();
1932	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1933	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
1934
1935	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1936
1937	ATF_REQUIRE_EQ(0, uvmexp.npages);
1938
1939	uvm_physseg_init_seg(upm, pgs);
1940
1941	ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
1942
1943	/*
1944	 * When called for first time, uvm_page_physload() removes the first PFN
1945	 *
1946	 * New avail start will be VALID_AVAIL_START_PFN_2 + 1
1947	 */
1948	ATF_CHECK_EQ(VALID_START_PFN_2, atop(p));
1949
1950	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
1951	    uvm_physseg_get_avail_start(upm));
1952
1953	ATF_CHECK_EQ(VALID_START_PFN_2 + 1, uvm_physseg_get_start(upm));
1954
1955	/* Rest of the stuff should remain the same */
1956	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
1957	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
1958}
1959
1960ATF_TC(uvm_page_physunload_end);
1961ATF_TC_HEAD(uvm_page_physunload_end, tc)
1962{
1963	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
1964	    call works without a panic(). Unloads from End of the segment.");
1965}
1966ATF_TC_BODY(uvm_page_physunload_end, tc)
1967{
1968	/*
1969	 * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
1970	 */
1971	paddr_t p = 0;
1972
1973	uvm_physseg_t upm;
1974
1975	setup();
1976	/* Note: start != avail_start to remove from end. */
1977	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
1978	    VALID_AVAIL_START_PFN_2 + 1, VALID_AVAIL_END_PFN_2,
1979	    VM_FREELIST_DEFAULT);
1980
1981	p = 0;
1982
1983	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
1984
1985	ATF_REQUIRE_EQ(0, uvmexp.npages);
1986
1987	ATF_REQUIRE(
1988		uvm_physseg_get_avail_start(upm) != uvm_physseg_get_start(upm));
1989
1990	ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
1991
1992	/*
1993	 * Remember if X is the upper limit the actual valid pointer is X - 1
1994	 *
1995	 * For example if 256 is the upper limit for 1MB memory, last valid
1996	 * pointer is 256 - 1 = 255
1997	 */
1998
1999	ATF_CHECK_EQ(VALID_END_PFN_2 - 1, atop(p));
2000
2001	/*
2002	 * When called for second time, uvm_page_physload() removes the last PFN
2003	 *
2004	 * New avail end will be VALID_AVAIL_END_PFN_2 - 1
2005	 * New end will be VALID_AVAIL_PFN_2 - 1
2006	 */
2007
2008	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2 - 1, uvm_physseg_get_avail_end(upm));
2009
2010	ATF_CHECK_EQ(VALID_END_PFN_2 - 1, uvm_physseg_get_end(upm));
2011
2012	/* Rest of the stuff should remain the same */
2013	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
2014	    uvm_physseg_get_avail_start(upm));
2015	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
2016}
2017
2018ATF_TC(uvm_page_physunload_none);
2019ATF_TC_HEAD(uvm_page_physunload_none, tc)
2020{
2021	atf_tc_set_md_var(tc, "descr", "Tests if the basic uvm_page_physunload()\
2022	    call works without a panic(). Does not unload from start or end \
2023	    because of non-aligned start / avail_start and end / avail_end \
2024	    respectively.");
2025}
2026ATF_TC_BODY(uvm_page_physunload_none, tc)
2027{
2028	psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
2029
2030	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
2031
2032	paddr_t p = 0;
2033
2034	uvm_physseg_t upm;
2035
2036	setup();
2037	/*
2038	 * Note: start != avail_start and end != avail_end.
2039	 *
2040	 * This prevents any unload from occuring.
2041	 */
2042	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
2043	    VALID_AVAIL_START_PFN_2 + 1, VALID_AVAIL_END_PFN_2 - 1,
2044	    VM_FREELIST_DEFAULT);
2045
2046	p = 0;
2047
2048	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2049
2050	ATF_REQUIRE_EQ(0, uvmexp.npages);
2051
2052	ATF_REQUIRE(
2053		uvm_physseg_get_avail_start(upm) != uvm_physseg_get_start(upm));
2054
2055	uvm_physseg_init_seg(upm, pgs);
2056
2057	ATF_CHECK_EQ(false, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
2058
2059	/* uvm_page_physload() will no longer unload memory */
2060	ATF_CHECK_EQ(0, p);
2061
2062	/* Rest of the stuff should remain the same */
2063	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2 + 1,
2064	    uvm_physseg_get_avail_start(upm));
2065	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2 - 1,
2066	    uvm_physseg_get_avail_end(upm));
2067	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
2068	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
2069}
2070
2071ATF_TC(uvm_page_physunload_delete_start);
2072ATF_TC_HEAD(uvm_page_physunload_delete_start, tc)
2073{
2074	atf_tc_set_md_var(tc, "descr", "Tests if the  uvm_page_physunload() \
2075	    works when the segment gets small enough to be deleted scenario. \
2076	    NOTE: This one works deletes from start.");
2077}
2078ATF_TC_BODY(uvm_page_physunload_delete_start, tc)
2079{
2080	/*
2081	 * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
2082	 */
2083	paddr_t p = 0;
2084
2085	uvm_physseg_t upm;
2086
2087	setup();
2088
2089	/*
2090	 * Setup the Nuke from Starting point
2091	 */
2092
2093	upm = uvm_page_physload(VALID_END_PFN_1 - 1, VALID_END_PFN_1,
2094	    VALID_AVAIL_END_PFN_1 - 1, VALID_AVAIL_END_PFN_1,
2095	    VM_FREELIST_DEFAULT);
2096
2097	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2098
2099	ATF_REQUIRE_EQ(0, uvmexp.npages);
2100
2101	/* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
2102#if VM_PHYSSEG_MAX > 1
2103	uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
2104	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
2105
2106	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
2107#endif
2108
2109#if VM_PHYSSEG_MAX == 1
2110	atf_tc_expect_signal(SIGABRT,
2111	    "cannot uvm_page_physunload() the last segment");
2112#endif
2113
2114	ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
2115
2116	ATF_CHECK_EQ(VALID_END_PFN_1 - 1, atop(p));
2117
2118	ATF_CHECK_EQ(1, uvm_physseg_get_entries());
2119
2120	/* The only node now is the one we inserted second. */
2121	upm = uvm_physseg_get_first();
2122
2123	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
2124	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
2125	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
2126	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
2127}
2128
2129ATF_TC(uvm_page_physunload_delete_end);
2130ATF_TC_HEAD(uvm_page_physunload_delete_end, tc)
2131{
2132	atf_tc_set_md_var(tc, "descr", "Tests if the  uvm_page_physunload() \
2133	    works when the segment gets small enough to be deleted scenario. \
2134	    NOTE: This one works deletes from end.");
2135}
2136ATF_TC_BODY(uvm_page_physunload_delete_end, tc)
2137{
2138	/*
2139	 * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
2140	 */
2141
2142	paddr_t p = 0;
2143
2144	uvm_physseg_t upm;
2145
2146	setup();
2147
2148	/*
2149	 * Setup the Nuke from Ending point
2150	 */
2151
2152	upm = uvm_page_physload(VALID_START_PFN_1, VALID_START_PFN_1 + 2,
2153	    VALID_AVAIL_START_PFN_1 + 1, VALID_AVAIL_START_PFN_1 + 2,
2154	    VM_FREELIST_DEFAULT);
2155
2156	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2157
2158	ATF_REQUIRE_EQ(0, uvmexp.npages);
2159
2160	/* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
2161#if VM_PHYSSEG_MAX > 1
2162	uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
2163	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
2164
2165	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
2166#endif
2167
2168#if VM_PHYSSEG_MAX == 1
2169	atf_tc_expect_signal(SIGABRT,
2170	    "cannot uvm_page_physunload() the last segment");
2171#endif
2172
2173	ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
2174
2175	p = 0;
2176
2177	ATF_CHECK_EQ(true, uvm_page_physunload(upm, VM_FREELIST_DEFAULT, &p));
2178
2179	ATF_CHECK_EQ(VALID_START_PFN_1 + 2, atop(p));
2180
2181	ATF_CHECK_EQ(1, uvm_physseg_get_entries());
2182
2183	/* The only node now is the one we inserted second. */
2184	upm = uvm_physseg_get_first();
2185
2186	ATF_CHECK_EQ(VALID_START_PFN_2, uvm_physseg_get_start(upm));
2187	ATF_CHECK_EQ(VALID_END_PFN_2, uvm_physseg_get_end(upm));
2188	ATF_CHECK_EQ(VALID_AVAIL_START_PFN_2, uvm_physseg_get_avail_start(upm));
2189	ATF_CHECK_EQ(VALID_AVAIL_END_PFN_2, uvm_physseg_get_avail_end(upm));
2190}
2191
2192ATF_TC(uvm_page_physunload_invalid);
2193ATF_TC_HEAD(uvm_page_physunload_invalid, tc)
2194{
2195	atf_tc_set_md_var(tc, "descr", "Tests if the  uvm_page_physunload() \
2196	    fails when then Free list does not match.");
2197}
2198ATF_TC_BODY(uvm_page_physunload_invalid, tc)
2199{
2200	psize_t npages = (VALID_END_PFN_2 - VALID_START_PFN_2);
2201
2202	struct vm_page *pgs = malloc(sizeof(struct vm_page) * npages);
2203
2204	paddr_t p = 0;
2205
2206	uvm_physseg_t upm;
2207
2208	setup();
2209	upm = uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
2210	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
2211
2212	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2213
2214	ATF_REQUIRE_EQ(0, uvmexp.npages);
2215
2216	uvm_physseg_init_seg(upm, pgs);
2217
2218	ATF_CHECK_EQ(false, uvm_page_physunload(upm, VM_FREELIST_FIRST4G, &p));
2219}
2220
2221ATF_TC(uvm_page_physunload_force);
2222ATF_TC_HEAD(uvm_page_physunload_force, tc)
2223{
2224	atf_tc_set_md_var(tc, "descr", "Tests if the basic \
2225	    uvm_page_physunload_force() including delete works without.");
2226}
2227ATF_TC_BODY(uvm_page_physunload_force, tc)
2228{
2229	/*
2230	 * Would uvmexp.npages reduce everytime an uvm_page_physunload is called?
2231	 */
2232	paddr_t p = 0;
2233
2234	uvm_physseg_t upm;
2235
2236	setup();
2237	upm = uvm_page_physload(VALID_START_PFN_1, VALID_END_PFN_1,
2238	    VALID_AVAIL_START_PFN_1, VALID_AVAIL_END_PFN_1, VM_FREELIST_DEFAULT);
2239
2240	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2241
2242	ATF_REQUIRE_EQ(0, uvmexp.npages);
2243
2244	/* Insert more than one segment iff VM_PHYSSEG_MAX > 1 */
2245#if VM_PHYSSEG_MAX > 1
2246	/*
2247	 * We have couple of physloads done this is bacause of the fact that if
2248	 * we physunload all the PFs from a given range and we have only one
2249	 * segment in total a panic() is called
2250	 */
2251	uvm_page_physload(VALID_START_PFN_2, VALID_END_PFN_2,
2252	    VALID_AVAIL_START_PFN_2, VALID_AVAIL_END_PFN_2, VM_FREELIST_DEFAULT);
2253
2254	ATF_REQUIRE_EQ(2, uvm_physseg_get_entries());
2255#endif
2256
2257#if VM_PHYSSEG_MAX == 1
2258	atf_tc_expect_signal(SIGABRT,
2259	    "cannot uvm_page_physunload() the last segment");
2260#endif
2261
2262	ATF_REQUIRE_EQ(VALID_AVAIL_START_PFN_1,
2263	    uvm_physseg_get_avail_start(upm));
2264
2265	for(paddr_t i = VALID_AVAIL_START_PFN_1;
2266	    i < VALID_AVAIL_END_PFN_1; i++) {
2267		ATF_CHECK_EQ(true,
2268		    uvm_page_physunload_force(upm, VM_FREELIST_DEFAULT, &p));
2269		ATF_CHECK_EQ(i, atop(p));
2270
2271		if(i + 1 < VALID_AVAIL_END_PFN_1)
2272			ATF_CHECK_EQ(i + 1, uvm_physseg_get_avail_start(upm));
2273	}
2274
2275	/*
2276	 * Now we try to retrieve the segment, which has been removed
2277	 * from the system through force unloading all the pages inside it.
2278	 */
2279	upm = uvm_physseg_find(VALID_AVAIL_END_PFN_1 - 1, NULL);
2280
2281	/* It should no longer exist */
2282	ATF_CHECK_EQ(NULL, upm);
2283
2284	ATF_CHECK_EQ(1, uvm_physseg_get_entries());
2285}
2286
2287ATF_TC(uvm_page_physunload_force_invalid);
2288ATF_TC_HEAD(uvm_page_physunload_force_invalid, tc)
2289{
2290	atf_tc_set_md_var(tc, "descr", "Tests if the invalid conditions for \
2291	    uvm_page_physunload_force_invalid().");
2292}
2293ATF_TC_BODY(uvm_page_physunload_force_invalid, tc)
2294{
2295	paddr_t p = 0;
2296
2297	uvm_physseg_t upm;
2298
2299	setup();
2300	upm = uvm_page_physload(VALID_START_PFN_2, VALID_START_PFN_2+ 1,
2301	    VALID_START_PFN_2, VALID_START_PFN_2, VM_FREELIST_DEFAULT);
2302
2303	ATF_REQUIRE_EQ(1, uvm_physseg_get_entries());
2304
2305	ATF_REQUIRE_EQ(0, uvmexp.npages);
2306
2307	ATF_CHECK_EQ(false,
2308	    uvm_page_physunload_force(upm, VM_FREELIST_DEFAULT, &p));
2309
2310	ATF_CHECK_EQ(0, p);
2311}
2312
2313ATF_TP_ADD_TCS(tp)
2314{
2315#if defined(UVM_HOTPLUG)
2316	/* Internal */
2317	ATF_TP_ADD_TC(tp, uvm_physseg_alloc_atboot_mismatch);
2318	ATF_TP_ADD_TC(tp, uvm_physseg_alloc_atboot_overrun);
2319	ATF_TP_ADD_TC(tp, uvm_physseg_alloc_sanity);
2320	ATF_TP_ADD_TC(tp, uvm_physseg_free_atboot_mismatch);
2321	ATF_TP_ADD_TC(tp, uvm_physseg_free_sanity);
2322#if VM_PHYSSEG_MAX > 1
2323	ATF_TP_ADD_TC(tp, uvm_physseg_atboot_free_leak);
2324#endif
2325#endif /* UVM_HOTPLUG */
2326
2327	ATF_TP_ADD_TC(tp, uvm_physseg_plug);
2328	ATF_TP_ADD_TC(tp, uvm_physseg_unplug);
2329
2330	/* Exported */
2331	ATF_TP_ADD_TC(tp, uvm_physseg_init);
2332	ATF_TP_ADD_TC(tp, uvm_page_physload_preload);
2333	ATF_TP_ADD_TC(tp, uvm_page_physload_postboot);
2334	ATF_TP_ADD_TC(tp, uvm_physseg_handle_immutable);
2335	ATF_TP_ADD_TC(tp, uvm_physseg_seg_chomp_slab);
2336	ATF_TP_ADD_TC(tp, uvm_physseg_alloc_from_slab);
2337	ATF_TP_ADD_TC(tp, uvm_physseg_init_seg);
2338	ATF_TP_ADD_TC(tp, uvm_physseg_get_start);
2339	ATF_TP_ADD_TC(tp, uvm_physseg_get_start_invalid);
2340	ATF_TP_ADD_TC(tp, uvm_physseg_get_end);
2341	ATF_TP_ADD_TC(tp, uvm_physseg_get_end_invalid);
2342	ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_start);
2343	ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_start_invalid);
2344	ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_end);
2345	ATF_TP_ADD_TC(tp, uvm_physseg_get_avail_end_invalid);
2346	ATF_TP_ADD_TC(tp, uvm_physseg_get_next);
2347	ATF_TP_ADD_TC(tp, uvm_physseg_get_next_invalid);
2348	ATF_TP_ADD_TC(tp, uvm_physseg_get_prev);
2349	ATF_TP_ADD_TC(tp, uvm_physseg_get_prev_invalid);
2350	ATF_TP_ADD_TC(tp, uvm_physseg_get_first);
2351	ATF_TP_ADD_TC(tp, uvm_physseg_get_last);
2352	ATF_TP_ADD_TC(tp, uvm_physseg_valid);
2353	ATF_TP_ADD_TC(tp, uvm_physseg_valid_invalid);
2354	ATF_TP_ADD_TC(tp, uvm_physseg_get_highest);
2355	ATF_TP_ADD_TC(tp, uvm_physseg_get_free_list);
2356	ATF_TP_ADD_TC(tp, uvm_physseg_get_start_hint);
2357	ATF_TP_ADD_TC(tp, uvm_physseg_set_start_hint);
2358	ATF_TP_ADD_TC(tp, uvm_physseg_set_start_hint_invalid);
2359	ATF_TP_ADD_TC(tp, uvm_physseg_get_pg);
2360
2361#ifdef __HAVE_PMAP_PHYSSEG
2362	ATF_TP_ADD_TC(tp, uvm_physseg_get_pmseg);
2363#endif
2364	ATF_TP_ADD_TC(tp, vm_physseg_find);
2365	ATF_TP_ADD_TC(tp, vm_physseg_find_invalid);
2366
2367	ATF_TP_ADD_TC(tp, uvm_page_physunload_start);
2368	ATF_TP_ADD_TC(tp, uvm_page_physunload_end);
2369	ATF_TP_ADD_TC(tp, uvm_page_physunload_none);
2370	ATF_TP_ADD_TC(tp, uvm_page_physunload_delete_start);
2371	ATF_TP_ADD_TC(tp, uvm_page_physunload_delete_end);
2372	ATF_TP_ADD_TC(tp, uvm_page_physunload_invalid);
2373	ATF_TP_ADD_TC(tp, uvm_page_physunload_force);
2374	ATF_TP_ADD_TC(tp, uvm_page_physunload_force_invalid);
2375
2376	return atf_no_error();
2377}
2378