Home | History | Annotate | Download | only in qemu
      1 /*
      2  * QEMU low level functions
      3  *
      4  * Copyright (c) 2003 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 #include <stdlib.h>
     25 #include <stdio.h>
     26 #include <stdarg.h>
     27 #include <string.h>
     28 #include <errno.h>
     29 #include <unistd.h>
     30 #include <fcntl.h>
     31 #ifdef CONFIG_SOLARIS
     32 #include <sys/types.h>
     33 #include <sys/statvfs.h>
     34 #endif
     35 
     36 /* Needed early for CONFIG_BSD etc. */
     37 #include "config-host.h"
     38 
     39 #ifdef _WIN32
     40 #include <windows.h>
     41 #elif defined(CONFIG_BSD)
     42 #include <stdlib.h>
     43 #else
     44 #include <malloc.h>
     45 #endif
     46 
     47 #include "qemu-common.h"
     48 #include "sysemu.h"
     49 
     50 #ifdef _WIN32
     51 #define WIN32_LEAN_AND_MEAN
     52 #include <windows.h>
     53 #elif defined(CONFIG_BSD)
     54 #include <stdlib.h>
     55 #else
     56 #include <malloc.h>
     57 #endif
     58 
     59 
     60 #if defined(_WIN32)
     61 void *qemu_memalign(size_t alignment, size_t size)
     62 {
     63     return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
     64 }
     65 
     66 void *qemu_vmalloc(size_t size)
     67 {
     68     /* FIXME: this is not exactly optimal solution since VirtualAlloc
     69        has 64Kb granularity, but at least it guarantees us that the
     70        memory is page aligned. */
     71     return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
     72 }
     73 
     74 void qemu_vfree(void *ptr)
     75 {
     76     VirtualFree(ptr, 0, MEM_RELEASE);
     77 }
     78 
     79 #else
     80 
     81 #if defined(CONFIG_KQEMU)
     82 
     83 #ifdef __OpenBSD__
     84 #include <sys/param.h>
     85 #include <sys/types.h>
     86 #include <sys/mount.h>
     87 #else
     88 #ifndef __FreeBSD__
     89 #include <sys/vfs.h>
     90 #endif
     91 #endif
     92 
     93 #include <sys/mman.h>
     94 #include <fcntl.h>
     95 
     96 static void *kqemu_vmalloc(size_t size)
     97 {
     98     static int phys_ram_fd = -1;
     99     static int phys_ram_size = 0;
    100     void *ptr;
    101 
    102 /* no need (?) for a dummy file on OpenBSD/FreeBSD */
    103 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
    104     int map_anon = MAP_ANON;
    105 #else
    106     int map_anon = 0;
    107     const char *tmpdir;
    108     char phys_ram_file[1024];
    109 #ifdef CONFIG_SOLARIS
    110     struct statvfs stfs;
    111 #else
    112     struct statfs stfs;
    113 #endif
    114 
    115     if (phys_ram_fd < 0) {
    116         tmpdir = getenv("QEMU_TMPDIR");
    117         if (!tmpdir)
    118 #ifdef CONFIG_SOLARIS
    119             tmpdir = "/tmp";
    120         if (statvfs(tmpdir, &stfs) == 0) {
    121 #else
    122             tmpdir = "/dev/shm";
    123         if (statfs(tmpdir, &stfs) == 0) {
    124 #endif
    125             int64_t free_space;
    126             int ram_mb;
    127 
    128             free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
    129             if ((ram_size + 8192 * 1024) >= free_space) {
    130                 ram_mb = (ram_size / (1024 * 1024));
    131                 fprintf(stderr,
    132                         "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
    133                         tmpdir, ram_mb);
    134                 if (strcmp(tmpdir, "/dev/shm") == 0) {
    135                     fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
    136                             "mount -o remount,size=%dm /dev/shm\n",
    137                             ram_mb + 16);
    138                 } else {
    139                     fprintf(stderr,
    140                             "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
    141                             "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
    142                             "temporary RAM file will be opened.\n");
    143                 }
    144                 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
    145                 exit(1);
    146             }
    147         }
    148         snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
    149                  tmpdir);
    150         phys_ram_fd = mkstemp(phys_ram_file);
    151         if (phys_ram_fd < 0) {
    152             fprintf(stderr,
    153                     "warning: could not create temporary file in '%s'.\n"
    154                     "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
    155                     "Using '/tmp' as fallback.\n",
    156                     tmpdir);
    157             snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
    158                      "/tmp");
    159             phys_ram_fd = mkstemp(phys_ram_file);
    160             if (phys_ram_fd < 0) {
    161                 fprintf(stderr, "Could not create temporary memory file '%s'\n",
    162                         phys_ram_file);
    163                 exit(1);
    164             }
    165         }
    166         unlink(phys_ram_file);
    167     }
    168     size = (size + 4095) & ~4095;
    169     ftruncate(phys_ram_fd, phys_ram_size + size);
    170 #endif /* !(__OpenBSD__ || __FreeBSD__ || __DragonFly__) */
    171     ptr = mmap(NULL,
    172                size,
    173                PROT_WRITE | PROT_READ, map_anon | MAP_SHARED,
    174                phys_ram_fd, phys_ram_size);
    175     if (ptr == MAP_FAILED) {
    176         fprintf(stderr, "Could not map physical memory\n");
    177         exit(1);
    178     }
    179     phys_ram_size += size;
    180     return ptr;
    181 }
    182 
    183 static void kqemu_vfree(void *ptr)
    184 {
    185     /* may be useful some day, but currently we do not need to free */
    186 }
    187 
    188 #endif
    189 
    190 void *qemu_memalign(size_t alignment, size_t size)
    191 {
    192 #if defined(_POSIX_C_SOURCE)
    193     int ret;
    194     void *ptr;
    195     ret = posix_memalign(&ptr, alignment, size);
    196     if (ret != 0)
    197         return NULL;
    198     return ptr;
    199 #elif defined(CONFIG_BSD)
    200     return valloc(size);
    201 #else
    202     return memalign(alignment, size);
    203 #endif
    204 }
    205 
    206 /* alloc shared memory pages */
    207 void *qemu_vmalloc(size_t size)
    208 {
    209 #if defined(CONFIG_KQEMU)
    210     if (kqemu_allowed)
    211         return kqemu_vmalloc(size);
    212 #endif
    213     return qemu_memalign(getpagesize(), size);
    214 }
    215 
    216 void qemu_vfree(void *ptr)
    217 {
    218 #if defined(CONFIG_KQEMU)
    219     if (kqemu_allowed)
    220         kqemu_vfree(ptr);
    221 #endif
    222     free(ptr);
    223 }
    224 
    225 #endif
    226 
    227 int qemu_create_pidfile(const char *filename)
    228 {
    229     char buffer[128];
    230     int len;
    231 #ifndef _WIN32
    232     int fd;
    233 
    234     fd = open(filename, O_RDWR | O_CREAT, 0600);
    235     if (fd == -1)
    236         return -1;
    237 
    238     if (lockf(fd, F_TLOCK, 0) == -1)
    239         return -1;
    240 
    241     len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
    242     if (write(fd, buffer, len) != len)
    243         return -1;
    244 #else
    245     HANDLE file;
    246     DWORD flags;
    247     OVERLAPPED overlap;
    248     BOOL ret;
    249 
    250     /* Open for writing with no sharing. */
    251     file = CreateFile(filename, GENERIC_WRITE, 0, NULL,
    252 		      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    253 
    254     if (file == INVALID_HANDLE_VALUE)
    255       return -1;
    256 
    257     flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
    258     overlap.hEvent = 0;
    259     /* Lock 1 byte. */
    260     ret = LockFileEx(file, flags, 0, 0, 1, &overlap);
    261     if (ret == 0)
    262       return -1;
    263 
    264     /* Write PID to file. */
    265     len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
    266     ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
    267 		      &overlap, NULL);
    268     if (ret == 0)
    269       return -1;
    270 #endif
    271     return 0;
    272 }
    273 
    274 #ifdef _WIN32
    275 
    276 /* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
    277 #define _W32_FT_OFFSET (116444736000000000ULL)
    278 
    279 int qemu_gettimeofday(qemu_timeval *tp)
    280 {
    281   union {
    282     unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
    283     FILETIME ft;
    284   }  _now;
    285 
    286   if(tp)
    287     {
    288       GetSystemTimeAsFileTime (&_now.ft);
    289       tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
    290       tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
    291     }
    292   /* Always return 0 as per Open Group Base Specifications Issue 6.
    293      Do not set errno on error.  */
    294   return 0;
    295 }
    296 
    297 int  ffs(int  val)
    298 {
    299 	int  nn;
    300 
    301 	for (nn = 0; nn < sizeof(int)*8; nn++)
    302 		if (val & (1 << nn))
    303 			return nn+1;
    304 
    305 	return 0;
    306 }
    307 
    308 #endif /* _WIN32 */
    309 
    310 
    311