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