Index: tests/sys/vm/pmap/Makefile =================================================================== --- /dev/null +++ tests/sys/vm/pmap/Makefile @@ -0,0 +1,5 @@ +SRCS=qpage.c +KMOD=qpage + +.include + Index: tests/sys/vm/pmap/qpage.c =================================================================== --- /dev/null +++ tests/sys/vm/pmap/qpage.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static MALLOC_DEFINE(M_QMAP, "qmap", "qmap buffers"); + +#define QMAP_NBUFS 2 + +static struct thread *qmap_thrs[QMAP_NBUFS] = {NULL}; + +static bool pass = true; + +struct qmap_buffer { + vm_page_t page; + struct mtx lock; + bool ready; + bool acked; +}; + +static struct qmap_buffer qmap_bufs[QMAP_NBUFS]; + +struct qmap_thread_arg { + struct qmap_buffer *write_buf; + struct qmap_buffer *read_buf; + unsigned int loops; + bool stop; + bool exit; +}; + +static struct qmap_thread_arg thread_args[QMAP_NBUFS]; + +static void +qmap_thread(void *context) +{ + struct qmap_thread_arg *arg = context; + uint8_t fill = 0; + + for (;;) { + vm_offset_t buf; + int i; + + mtx_lock(&(arg->write_buf->lock)); + if (!arg->stop && !arg->write_buf->acked) + mtx_sleep(&(arg->write_buf->acked), &(arg->write_buf->lock), 0, "qmap_write", 0); + arg->write_buf->acked = false; + if (!arg->stop) { + buf = pmap_quick_enter_page(arg->write_buf->page); + memset((void*)buf, (int)fill, PAGE_SIZE); + pmap_quick_remove_page(buf); + arg->write_buf->ready = true; + wakeup(&(arg->write_buf->ready)); + } + mtx_unlock(&(arg->write_buf->lock)); + + mtx_lock(&(arg->read_buf->lock)); + if (!arg->exit && !arg->read_buf->ready) + mtx_sleep(&(arg->read_buf->ready), &(arg->read_buf->lock), 0, "qmap_read", 0); + arg->read_buf->ready = false; + if (arg->exit) { + mtx_unlock(&(arg->read_buf->lock)); + kthread_exit(); + } + buf = pmap_quick_enter_page(arg->read_buf->page); + for (i = 0; i < PAGE_SIZE; ++i) + { + if (((uint8_t*)buf)[i] != fill) + { + pass = false; + break; + } + } + pmap_quick_remove_page(buf); + arg->read_buf->acked = true; + wakeup(&(arg->read_buf->acked)); + mtx_unlock(&(arg->read_buf->lock)); + if (i < PAGE_SIZE) + printf("Expected value 0x%x at buffer[%d]\n", fill, i); + ++fill; + ++(arg->loops); + } +} + +static void +qmap_mod_cleanup() +{ + for (int i = 0; i < QMAP_NBUFS; ++i) { + mtx_lock(&(thread_args[i].write_buf->lock)); + thread_args[i].stop = true; + wakeup(&(thread_args[i].write_buf->acked)); + mtx_unlock(&(thread_args[i].write_buf->lock)); + mtx_lock(&(thread_args[i].read_buf->lock)); + thread_args[i].exit = true; + wakeup(&(thread_args[i].read_buf->ready)); + mtx_sleep(qmap_thrs[i], &(thread_args[i].read_buf->lock), 0, "qmap_join", 0); + mtx_unlock(&(thread_args[i].read_buf->lock)); + } + for (int i = 0; i < QMAP_NBUFS; ++i) { + if (qmap_bufs[i].page != NULL) { + vm_page_unwire(qmap_bufs[i].page, PQ_INACTIVE); + vm_page_free(qmap_bufs[i].page); + } + mtx_destroy(&(qmap_bufs[i].lock)); + } +} + +static int +qmap_mod_handler(module_t mod, int what, void *arg) +{ + int ret = 0; + + switch(what) { + case MOD_LOAD: + for (int i = 0; i < QMAP_NBUFS; ++i) { + qmap_bufs[i].ready = false; + qmap_bufs[i].acked = true; + mtx_init(&(qmap_bufs[i].lock), "qmap test lock", NULL, MTX_DEF); + qmap_bufs[i].page = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED); + if (qmap_bufs[i].page == NULL) + ret = ENOMEM; + } + thread_args[0].write_buf = &qmap_bufs[0]; + thread_args[0].read_buf = &qmap_bufs[1]; + thread_args[0].stop = false; + thread_args[0].exit = false; + thread_args[0].loops = 0; + thread_args[1].write_buf = &qmap_bufs[1]; + thread_args[1].read_buf = &qmap_bufs[0]; + thread_args[1].stop = false; + thread_args[1].exit = false; + thread_args[1].loops = 0; + for (int i = 0; i < QMAP_NBUFS && ret == 0; ++i) + ret = kthread_add(&qmap_thread, &thread_args[i], NULL, &qmap_thrs[i], 0, 0, "qmap_thread[%d]", i); + if (ret != 0) + qmap_mod_cleanup(); + return ret; + case MOD_UNLOAD: + case MOD_SHUTDOWN: + qmap_mod_cleanup(); + printf("Ran %u,%u loops; result: %s\n", thread_args[0].loops, + thread_args[1].loops, (pass ? "PASS" : "FAIL")); + return 0; + default: + return 0; + } +} + +static moduledata_t qmap_mod_data = { + "qmap", + qmap_mod_handler, + NULL +}; + +DECLARE_MODULE(qmap, qmap_mod_data, SI_SUB_DRIVERS, SI_ORDER_ANY); +MODULE_VERSION(qmap, 1);