From 2c1656af6bf2dc8e9ba173312a4484bf1ae2d7b6 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 16 Nov 2022 15:01:53 -0500 Subject: [PATCH 24/52] mips: Add a skeleton "tlbdemo" driver --- sys/conf/files.mips | 1 + sys/mips/mips/tlbdemo.c | 253 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 sys/mips/mips/tlbdemo.c diff --git a/sys/conf/files.mips b/sys/conf/files.mips index 4e1903e726eb..dfa9ed8a8919 100644 --- a/sys/conf/files.mips +++ b/sys/conf/files.mips @@ -43,6 +43,7 @@ mips/mips/bcopy.S standard mips/mips/swtch.S standard mips/mips/sys_machdep.c standard mips/mips/tlb.c standard +mips/mips/tlbdemo.c standard mips/mips/trap.c standard mips/mips/uio_machdep.c standard mips/mips/uma_machdep.c standard diff --git a/sys/mips/mips/tlbdemo.c b/sys/mips/mips/tlbdemo.c new file mode 100644 index 000000000000..4af4ccea0ed6 --- /dev/null +++ b/sys/mips/mips/tlbdemo.c @@ -0,0 +1,253 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2022 Juniper Networks Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +/* + * tlbdemo: A dummy driver which reserves contiguous physical memory at boot + * time and allows it to be mapped into userspace using largepage shared memory + * objects. + * + * The driver creates one global shared memory object for each page size index. + * A page size index is a valid index into the pagesizes[] array, which records + * the valid superpage sizes for the system. During boot, the shared memory + * objects are initialized and populated with contiguous memory. Then, the + * driver creates one /dev node per page size, so /dev/tlbdemo1 is used to map + * 2MB pages, /dev/tlbdemo2 is used to map 8MB pages, and so on. + * + * When a tlbdemo device node is opened, the driver returns a descriptor for the + * corresponding shared memory object. Userspace can then use mmap() to map the + * shared memory object. + * + * In the kernel, the shared memory currently must be accessed via the direct + * map. The tlbdemo_map() function returns a pointer to the requested region. + * In particular, a reservation of multiple large pages is not physically + * contiguous. In the kernel each large page is accessed through the direct + * map, and so the driver has to manage a pointer to each large page. With some + * additional work it would be possible to map large pages contiguously into the + * kernel map. + */ + +static struct sx tlbdemo_mtx; + +struct tlbdemo_store { + struct shmfd *shmfd; + vm_size_t size; + int count; +}; + +/* + * Number of pages of each size to reserve at boot time. + */ +static struct tlbdemo_store tlbdemo_reservations[MAXPAGESIZES] = { + [1] = { .count = 1 }, /* 2MB */ + [2] = { .count = 1 }, /* 8MB */ + [3] = { .count = 1 }, /* 32MB */ + [4] = { .count = 1 }, /* 128MB */ +#ifdef notyet + [5] = { .count = 1 }, /* 512MB */ +#endif +}; + +/* + * Get a pointer to the large page of size pagesizes[psind] at offset + * offset * pagesizes[psind]. + */ +static void * __unused +tlbdemo_map(int psind, u_int offset) +{ + struct tlbdemo_store *s; + vm_page_t m; + vm_pindex_t pi; + + if (psind < 1 || psind >= MAXPAGESIZES) + return (NULL); + s = &tlbdemo_reservations[psind]; + if (s->shmfd == NULL || offset >= s->count) + return (NULL); + + pi = atop(offset * s->size); + VM_OBJECT_RLOCK(s->shmfd->shm_object); + m = vm_page_lookup(s->shmfd->shm_object, pi); + KASSERT(m != NULL, + ("%s: no page found, psind %d pi %#lx", __func__, psind, pi)); + VM_OBJECT_RUNLOCK(s->shmfd->shm_object); + + return ((void *)MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(m))); +} + +#if 0 +/* + * Populate the shared memory with 0xa, just to verify that userspace is mapping + * the same physical pages. + */ +static void +tlbdemo_write(void) +{ + struct tlbdemo_store *s; + + for (int i = 1; i < MAXPAGESIZES; i++) { + s = &tlbdemo_reservations[i]; + if (s->shmfd == NULL) + continue; + for (int j = 0; j < s->count; j++) { + void *addr = tlbdemo_map(i, j); + memset(addr, 0xa, s->size); + } + } +} +SYSINIT(tlbdemo_write, SI_SUB_SYSV_SHM + 2, SI_ORDER_ANY, tlbdemo_write, NULL); +#endif + +static void +tlbdemo_store(void *arg __unused) +{ + struct shm_largepage_conf conf; + struct shmfd *shmfd; + struct tlbdemo_store *s; + int error; + + for (int i = 1; i < MAXPAGESIZES; i++) { + s = &tlbdemo_reservations[i]; + s->size = pagesizes[i]; + + shmfd = shm_alloc(curthread->td_ucred, 0600, true); + if (shmfd == NULL) { + printf("%s:%d\n", __func__, __LINE__); + break; + } + conf.psind = i; + conf.alloc_policy = SHM_LARGEPAGE_ALLOC_NOWAIT; + error = shm_largepage_setconf(shmfd, &conf); + if (error != 0) { + printf("%s: failed to set largepage conf: %d\n", + __func__, error); + shm_drop(shmfd); + continue; + } + + error = shm_dotruncate(shmfd, s->count * s->size); + if (error != 0) { + printf("%s: failed to truncate largepage obj: %d\n", + __func__, error); + shm_drop(shmfd); + continue; + } + + s->shmfd = shmfd; + } +} +SYSINIT(tlbdemo_store, SI_SUB_SYSV_SHM + 1, SI_ORDER_ANY, tlbdemo_store, + NULL); + +static int +tlbdemo_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) +{ + struct tlbdemo_store *s; + int error; + + error = 0; + + sx_xlock(&tlbdemo_mtx); + s = dev->si_drv1; + if (s->shmfd != NULL) { + shm_hold(s->shmfd); + shm_finit(s->shmfd, fflags & (FREAD | FWRITE), fp); + } else { + error = ENOENT; + } + sx_xunlock(&tlbdemo_mtx); + return (0); +} + +static struct cdevsw tlbdemo_cdevsw = { + .d_name = "tlbdemo", + .d_version = D_VERSION, + .d_fdopen = tlbdemo_fdopen, +}; + +static int +tlbdemo_modevent(module_t mod __unused, int type, void *data __unused) +{ + static struct cdev *tlbdemo_dev[MAXPAGESIZES]; + struct make_dev_args args; + int error; + + switch (type) { + case MOD_LOAD: + sx_init(&tlbdemo_mtx, "tlbdemo"); + for (int i = 1; i < MAXPAGESIZES; i++) { + make_dev_args_init(&args); + args.mda_devsw = &tlbdemo_cdevsw; + args.mda_uid = UID_ROOT; + args.mda_gid = GID_WHEEL; + args.mda_mode = 0600; + args.mda_si_drv1 = &tlbdemo_reservations[i]; + args.mda_si_drv2 = NULL; + error = make_dev_s(&args, &tlbdemo_dev[i], "tlbdemo%d", i); + if (error != 0) + break; + } + break; + case MOD_UNLOAD: + for (int i = 1; i < MAXPAGESIZES; i++) { + if (tlbdemo_dev[i] != NULL) { + destroy_dev(tlbdemo_dev[i]); + tlbdemo_dev[i] = NULL; + } + } + sx_destroy(&tlbdemo_mtx); + break; + } + return (0); +} +DEV_MODULE(tlbdemo, tlbdemo_modevent, NULL); +MODULE_VERSION(tlbdemo, 1); -- 2.41.0