$NetBSD$ --- src/arch/netbsd/mapping/mapfile.c.orig 2017-11-02 06:34:44.092669600 +0000 +++ src/arch/netbsd/mapping/mapfile.c @@ -0,0 +1,299 @@ +/* + * (C) Copyright 1992, ..., 2014 the "DOSEMU-Development-Team". + * + * for details see file COPYING in the DOSEMU distribution + */ + +/* + * Purpose: memory mapping library, posix SHM and file backends. + * + * Authors: Stas Sergeev, Bart Oldeman. + * Initially started by Hans Lermen, old copyrights below: + */ +/* file mapfile.c + * file mapping driver + * Hans Lermen, lermen@fgan.de + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include + + +#include "emu.h" +#include "mapping.h" +#include "smalloc.h" +#include "utilities.h" + +/* ------------------------------------------------------------ */ + +static smpool pgmpool; +static int mpool_numpages = (32 * 1024) / 4; +static char *mpool = 0; + +static int tmpfile_fd = -1; + +static void *alias_mapping_file(int cap, void *target, size_t mapsize, int protect, void *source) +{ + int fixed = 0; + off_t offs = (char *)source - mpool; + void *addr; + + if (offs < 0 || (offs+mapsize >= (mpool_numpages*PAGE_SIZE))) { + Q_printf("MAPPING: alias_map to address outside of temp file\n"); + errno = EINVAL; + return MAP_FAILED; + } + if (target != (void *)-1) + fixed = MAP_FIXED; + else + target = NULL; + addr = mmap(target, mapsize, protect, MAP_SHARED | fixed, tmpfile_fd, offs); + if (addr == MAP_FAILED) { + addr = mmap(target, mapsize, protect & ~PROT_EXEC, MAP_SHARED | fixed, + tmpfile_fd, offs); + if (addr != MAP_FAILED) + mprotect(addr, mapsize, protect); + } +#if 1 + Q_printf("MAPPING: alias_map, fileoffs %llx to %p size %zx, result %p\n", + (long long)offs, target, mapsize, addr); +#endif + return addr; +} + +static void discardtempfile(void) +{ + close(tmpfile_fd); + tmpfile_fd = -1; +} + +static int open_mapping_f(int cap) +{ + int mapsize, estsize, padsize; + + if (cap) Q_printf("MAPPING: open, cap=%s\n", + decode_mapping_cap(cap)); + + padsize = 4*1024; + + /* first estimate the needed size of the mapfile */ + mapsize = HMASIZE >> 10; /* HMA */ + /* VGAEMU */ + mapsize += config.vgaemu_memsize ? config.vgaemu_memsize : 1024; + mapsize += config.ems_size; /* EMS */ + mapsize += LOWMEM_SIZE >> 10; /* Low Mem */ + estsize = mapsize; + /* keep heap fragmentation in mind */ + mapsize += (mapsize/4 < padsize ? padsize : mapsize/4); + mpool_numpages = mapsize / 4; + mapsize = mpool_numpages * PAGE_SIZE; /* make sure we are page aligned */ + + ftruncate(tmpfile_fd, 0); + if (ftruncate(tmpfile_fd, mapsize) == -1) { + if (!cap) + error("MAPPING: cannot size temp file pool, %s\n",strerror(errno)); + discardtempfile(); + if (!cap)return 0; + leavedos(2); + } + /* /dev/shm may be mounted noexec, and then mounting PROT_EXEC fails. + However mprotect may work around this (maybe not in future kernels) + */ + mpool = mmap(0, mapsize, PROT_READ|PROT_WRITE, + MAP_SHARED, tmpfile_fd, 0); + if (mpool == MAP_FAILED || + mprotect(mpool, mapsize, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + char *err = strerror(errno); + char s[] = "MAPPING: cannot size temp file pool, %s\n"; + discardtempfile(); + if (!cap) { + Q_printf(s,err); + return 0; + } + leavedos(2); + } + /* the memory pool itself can just be rw though */ + mprotect(mpool, mapsize, PROT_READ|PROT_WRITE); + Q_printf("MAPPING: open, mpool (min %dK) is %d Kbytes at %p-%p\n", + estsize, mapsize/1024, mpool, mpool+mapsize-1); + sminit(&pgmpool, mpool, mapsize); + + /* + * Now handle individual cases. + * Don't forget that each of the below code pieces should only + * be executed once ! + */ + +#if 0 + if (cap & MAPPING_OTHER) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_EMS) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_DPMI) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_VIDEO) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_VGAEMU) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_HGC) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_HMA) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_SHARED) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_INIT_HWRAM) { + /* none for now */ + } +#endif +#if 0 + if (cap & MAPPING_INIT_LOWRAM) { + /* none for now */ + } +#endif + + return 1; +} + +static int open_mapping_file(int cap) +{ + if (tmpfile_fd < 0) { + tmpfile_fd = fileno(tmpfile()); + open_mapping_f(cap); + } + return 1; +} + +#ifdef HAVE_SHM_OPEN +static int open_mapping_pshm(int cap) +{ + char *name; + int ret; + + if (tmpfile_fd < 0) { + ret = asprintf(&name, "%s%d", "dosemu_", getpid()); + assert(ret != -1); + + tmpfile_fd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (tmpfile_fd == -1) { + free(name); + return 0; + } + shm_unlink(name); + free(name); + if (!open_mapping_f(cap)) + return 0; + } + return 1; +} +#endif + +static void close_mapping_file(int cap) +{ + Q_printf("MAPPING: close, cap=%s\n", decode_mapping_cap(cap)); + if (cap == MAPPING_ALL && tmpfile_fd != -1) discardtempfile(); +} + +static void *alloc_mapping_file(int cap, size_t mapsize) +{ + Q__printf("MAPPING: alloc, cap=%s, mapsize=%zx\n", cap, mapsize); + return smalloc(&pgmpool, mapsize); +} + +static void free_mapping_file(int cap, void *addr, size_t mapsize) +/* NOTE: addr needs to be the same as what was supplied by alloc_mapping_file */ +{ + Q__printf("MAPPING: free, cap=%s, addr=%p, mapsize=%zx\n", + cap, addr, mapsize); + smfree(&pgmpool, addr); +} + +/* + * NOTE: DPMI relies on realloc_mapping() _not_ changing the address ('addr'), + * when shrinking the memory region. + */ +static void *realloc_mapping_file(int cap, void *addr, size_t oldsize, size_t newsize) +{ + Q__printf("MAPPING: realloc, cap=%s, addr=%p, oldsize=%zx, newsize=%zx\n", + cap, addr, oldsize, newsize); + if (cap & (MAPPING_EMS | MAPPING_DPMI)) { + int size = smget_area_size(&pgmpool, addr); + void *addr_; + + if (!size || size != oldsize) return (void *)-1; + if (size == newsize) return addr; + /* NOTE: smrealloc() does not change addr, + * when shrinking the memory region. + */ + addr_ = smrealloc(&pgmpool, addr, newsize); + if (!addr_) { + Q_printf("MAPPING: pgrealloc(0x%p,0x%zx,) failed\n", + addr, newsize); + return (void *)-1; + } + return addr_; + } + return (void *)-1; +} + +static int munmap_mapping_file(int cap, void *addr, size_t mapsize) +{ + Q__printf("MAPPING: unmap, cap=%s, addr=%p, size=%zx\n", + cap, addr, mapsize); + return munmap(addr, mapsize); +} + +#ifdef HAVE_SHM_OPEN +struct mappingdrivers mappingdriver_shm = { + "mapshm", + "Posix SHM mapping", + open_mapping_pshm, + close_mapping_file, + alloc_mapping_file, + free_mapping_file, + realloc_mapping_file, + munmap_mapping_file, + alias_mapping_file +}; +#endif + +struct mappingdrivers mappingdriver_file = { + "mapfile", + "temp file mapping", + open_mapping_file, + close_mapping_file, + alloc_mapping_file, + free_mapping_file, + realloc_mapping_file, + munmap_mapping_file, + alias_mapping_file +};