]>
Commit | Line | Data |
---|---|---|
c1b0b93b JS |
1 | /* |
2 | * os-win32.c | |
3 | * | |
4 | * Copyright (c) 2003-2008 Fabrice Bellard | |
c6196440 | 5 | * Copyright (c) 2010-2016 Red Hat, Inc. |
c1b0b93b JS |
6 | * |
7 | * QEMU library functions for win32 which are shared between QEMU and | |
8 | * the QEMU tools. | |
9 | * | |
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
11 | * of this software and associated documentation files (the "Software"), to deal | |
12 | * in the Software without restriction, including without limitation the rights | |
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
14 | * copies of the Software, and to permit persons to whom the Software is | |
15 | * furnished to do so, subject to the following conditions: | |
16 | * | |
17 | * The above copyright notice and this permission notice shall be included in | |
18 | * all copies or substantial portions of the Software. | |
19 | * | |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
23 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
26 | * THE SOFTWARE. | |
e637aa66 SW |
27 | * |
28 | * The implementation of g_poll (functions poll_rest, g_poll) at the end of | |
29 | * this file are based on code from GNOME glib-2 and use a different license, | |
30 | * see the license comment there. | |
c1b0b93b | 31 | */ |
a8d25326 | 32 | |
aafd7584 | 33 | #include "qemu/osdep.h" |
c1b0b93b | 34 | #include <windows.h> |
da34e65c | 35 | #include "qapi/error.h" |
1de7afc9 | 36 | #include "qemu/main-loop.h" |
c1b0b93b | 37 | #include "trace.h" |
1de7afc9 | 38 | #include "qemu/sockets.h" |
f348b6d1 | 39 | #include "qemu/cutils.h" |
8dbe22c6 | 40 | #include "qemu/error-report.h" |
dfbd0b87 | 41 | #include <malloc.h> |
c1b0b93b | 42 | |
e2ea3515 LE |
43 | /* this must come after including "trace.h" */ |
44 | #include <shlobj.h> | |
45 | ||
714efd54 DH |
46 | static int get_allocation_granularity(void) |
47 | { | |
48 | SYSTEM_INFO system_info; | |
49 | ||
50 | GetSystemInfo(&system_info); | |
51 | return system_info.dwAllocationGranularity; | |
52 | } | |
53 | ||
8dbe22c6 DH |
54 | void *qemu_anon_ram_alloc(size_t size, uint64_t *align, bool shared, |
55 | bool noreserve) | |
c1b0b93b JS |
56 | { |
57 | void *ptr; | |
58 | ||
8dbe22c6 DH |
59 | if (noreserve) { |
60 | /* | |
61 | * We need a MEM_COMMIT before accessing any memory in a MEM_RESERVE | |
62 | * area; we cannot easily mimic POSIX MAP_NORESERVE semantics. | |
63 | */ | |
64 | error_report("Skipping reservation of swap space is not supported."); | |
65 | return NULL; | |
66 | } | |
67 | ||
39228250 | 68 | ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); |
6eebf958 | 69 | trace_qemu_anon_ram_alloc(size, ptr); |
714efd54 DH |
70 | |
71 | if (ptr && align) { | |
72 | *align = MAX(get_allocation_granularity(), getpagesize()); | |
73 | } | |
c1b0b93b JS |
74 | return ptr; |
75 | } | |
76 | ||
e7a09b92 PB |
77 | void qemu_anon_ram_free(void *ptr, size_t size) |
78 | { | |
79 | trace_qemu_anon_ram_free(ptr, size); | |
80 | if (ptr) { | |
81 | VirtualFree(ptr, 0, MEM_RELEASE); | |
82 | } | |
83 | } | |
84 | ||
7c3afc85 | 85 | #ifndef _POSIX_THREAD_SAFE_FUNCTIONS |
d3e8f957 SW |
86 | /* FIXME: add proper locking */ |
87 | struct tm *gmtime_r(const time_t *timep, struct tm *result) | |
88 | { | |
89 | struct tm *p = gmtime(timep); | |
90 | memset(result, 0, sizeof(*result)); | |
91 | if (p) { | |
92 | *result = *p; | |
93 | p = result; | |
94 | } | |
95 | return p; | |
96 | } | |
97 | ||
98 | /* FIXME: add proper locking */ | |
99 | struct tm *localtime_r(const time_t *timep, struct tm *result) | |
100 | { | |
101 | struct tm *p = localtime(timep); | |
102 | memset(result, 0, sizeof(*result)); | |
103 | if (p) { | |
104 | *result = *p; | |
105 | p = result; | |
106 | } | |
107 | return p; | |
108 | } | |
7c3afc85 | 109 | #endif /* _POSIX_THREAD_SAFE_FUNCTIONS */ |
d3e8f957 | 110 | |
b16a44e1 | 111 | static int socket_error(void) |
c6196440 DB |
112 | { |
113 | switch (WSAGetLastError()) { | |
114 | case 0: | |
115 | return 0; | |
116 | case WSAEINTR: | |
117 | return EINTR; | |
118 | case WSAEINVAL: | |
119 | return EINVAL; | |
120 | case WSA_INVALID_HANDLE: | |
121 | return EBADF; | |
122 | case WSA_NOT_ENOUGH_MEMORY: | |
123 | return ENOMEM; | |
124 | case WSA_INVALID_PARAMETER: | |
125 | return EINVAL; | |
126 | case WSAENAMETOOLONG: | |
127 | return ENAMETOOLONG; | |
128 | case WSAENOTEMPTY: | |
129 | return ENOTEMPTY; | |
130 | case WSAEWOULDBLOCK: | |
131 | /* not using EWOULDBLOCK as we don't want code to have | |
132 | * to check both EWOULDBLOCK and EAGAIN */ | |
133 | return EAGAIN; | |
134 | case WSAEINPROGRESS: | |
135 | return EINPROGRESS; | |
136 | case WSAEALREADY: | |
137 | return EALREADY; | |
138 | case WSAENOTSOCK: | |
139 | return ENOTSOCK; | |
140 | case WSAEDESTADDRREQ: | |
141 | return EDESTADDRREQ; | |
142 | case WSAEMSGSIZE: | |
143 | return EMSGSIZE; | |
144 | case WSAEPROTOTYPE: | |
145 | return EPROTOTYPE; | |
146 | case WSAENOPROTOOPT: | |
147 | return ENOPROTOOPT; | |
148 | case WSAEPROTONOSUPPORT: | |
149 | return EPROTONOSUPPORT; | |
150 | case WSAEOPNOTSUPP: | |
151 | return EOPNOTSUPP; | |
152 | case WSAEAFNOSUPPORT: | |
153 | return EAFNOSUPPORT; | |
154 | case WSAEADDRINUSE: | |
155 | return EADDRINUSE; | |
156 | case WSAEADDRNOTAVAIL: | |
157 | return EADDRNOTAVAIL; | |
158 | case WSAENETDOWN: | |
159 | return ENETDOWN; | |
160 | case WSAENETUNREACH: | |
161 | return ENETUNREACH; | |
162 | case WSAENETRESET: | |
163 | return ENETRESET; | |
164 | case WSAECONNABORTED: | |
165 | return ECONNABORTED; | |
166 | case WSAECONNRESET: | |
167 | return ECONNRESET; | |
168 | case WSAENOBUFS: | |
169 | return ENOBUFS; | |
170 | case WSAEISCONN: | |
171 | return EISCONN; | |
172 | case WSAENOTCONN: | |
173 | return ENOTCONN; | |
174 | case WSAETIMEDOUT: | |
175 | return ETIMEDOUT; | |
176 | case WSAECONNREFUSED: | |
177 | return ECONNREFUSED; | |
178 | case WSAELOOP: | |
179 | return ELOOP; | |
180 | case WSAEHOSTUNREACH: | |
181 | return EHOSTUNREACH; | |
182 | default: | |
183 | return EIO; | |
184 | } | |
185 | } | |
186 | ||
894022e6 LV |
187 | void qemu_set_block(int fd) |
188 | { | |
189 | unsigned long opt = 0; | |
190 | WSAEventSelect(fd, NULL, 0); | |
191 | ioctlsocket(fd, FIONBIO, &opt); | |
192 | } | |
193 | ||
194 | int qemu_try_set_nonblock(int fd) | |
195 | { | |
196 | unsigned long opt = 1; | |
197 | if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) { | |
198 | return -socket_error(); | |
199 | } | |
894022e6 LV |
200 | return 0; |
201 | } | |
202 | ||
203 | void qemu_set_nonblock(int fd) | |
204 | { | |
205 | (void)qemu_try_set_nonblock(fd); | |
206 | } | |
207 | ||
208 | int socket_set_fast_reuse(int fd) | |
209 | { | |
210 | /* Enabling the reuse of an endpoint that was used by a socket still in | |
211 | * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows | |
212 | * fast reuse is the default and SO_REUSEADDR does strange things. So we | |
213 | * don't have to do anything here. More info can be found at: | |
214 | * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */ | |
215 | return 0; | |
216 | } | |
217 | ||
9549e764 JS |
218 | int inet_aton(const char *cp, struct in_addr *ia) |
219 | { | |
220 | uint32_t addr = inet_addr(cp); | |
221 | if (addr == 0xffffffff) { | |
e637aa66 | 222 | return 0; |
9549e764 JS |
223 | } |
224 | ia->s_addr = addr; | |
225 | return 1; | |
226 | } | |
227 | ||
228 | void qemu_set_cloexec(int fd) | |
229 | { | |
230 | } | |
dc786bc9 | 231 | |
cbcfa041 PB |
232 | int qemu_get_thread_id(void) |
233 | { | |
234 | return GetCurrentThreadId(); | |
235 | } | |
e2ea3515 LE |
236 | |
237 | char * | |
1fbf2665 | 238 | qemu_get_local_state_dir(void) |
e2ea3515 LE |
239 | { |
240 | HRESULT result; | |
241 | char base_path[MAX_PATH+1] = ""; | |
242 | ||
243 | result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, | |
244 | /* SHGFP_TYPE_CURRENT */ 0, base_path); | |
245 | if (result != S_OK) { | |
246 | /* misconfigured environment */ | |
247 | g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result); | |
248 | abort(); | |
249 | } | |
1fbf2665 | 250 | return g_strdup(base_path); |
e2ea3515 | 251 | } |
13401ba0 SH |
252 | |
253 | void qemu_set_tty_echo(int fd, bool echo) | |
254 | { | |
255 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | |
256 | DWORD dwMode = 0; | |
257 | ||
258 | if (handle == INVALID_HANDLE_VALUE) { | |
259 | return; | |
260 | } | |
261 | ||
262 | GetConsoleMode(handle, &dwMode); | |
263 | ||
264 | if (echo) { | |
265 | SetConsoleMode(handle, dwMode | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT); | |
266 | } else { | |
267 | SetConsoleMode(handle, | |
268 | dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT)); | |
269 | } | |
270 | } | |
10f5bff6 | 271 | |
9386a4a7 | 272 | static const char *exec_dir; |
10f5bff6 FZ |
273 | |
274 | void qemu_init_exec_dir(const char *argv0) | |
275 | { | |
276 | ||
277 | char *p; | |
278 | char buf[MAX_PATH]; | |
279 | DWORD len; | |
280 | ||
a4c13869 PB |
281 | if (exec_dir) { |
282 | return; | |
283 | } | |
284 | ||
10f5bff6 FZ |
285 | len = GetModuleFileName(NULL, buf, sizeof(buf) - 1); |
286 | if (len == 0) { | |
287 | return; | |
288 | } | |
289 | ||
290 | buf[len] = 0; | |
291 | p = buf + len - 1; | |
292 | while (p != buf && *p != '\\') { | |
293 | p--; | |
294 | } | |
295 | *p = 0; | |
296 | if (access(buf, R_OK) == 0) { | |
a4c13869 | 297 | exec_dir = g_strdup(buf); |
9386a4a7 PB |
298 | } else { |
299 | exec_dir = CONFIG_BINDIR; | |
10f5bff6 FZ |
300 | } |
301 | } | |
302 | ||
a4c13869 | 303 | const char *qemu_get_exec_dir(void) |
10f5bff6 | 304 | { |
a4c13869 | 305 | return exec_dir; |
10f5bff6 | 306 | } |
5a007547 | 307 | |
a28c2f2d | 308 | int getpagesize(void) |
38183310 PB |
309 | { |
310 | SYSTEM_INFO system_info; | |
311 | ||
312 | GetSystemInfo(&system_info); | |
313 | return system_info.dwPageSize; | |
314 | } | |
315 | ||
1e356fc1 JK |
316 | void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, |
317 | Error **errp) | |
38183310 PB |
318 | { |
319 | int i; | |
8e3b0cbb | 320 | size_t pagesize = qemu_real_host_page_size(); |
38183310 PB |
321 | |
322 | memory = (memory + pagesize - 1) & -pagesize; | |
323 | for (i = 0; i < memory / pagesize; i++) { | |
324 | memset(area + pagesize * i, 0, 1); | |
325 | } | |
326 | } | |
d57e4e48 | 327 | |
7dc9ae43 MP |
328 | char *qemu_get_pid_name(pid_t pid) |
329 | { | |
330 | /* XXX Implement me */ | |
331 | abort(); | |
332 | } | |
333 | ||
334 | ||
57cb38b3 DB |
335 | pid_t qemu_fork(Error **errp) |
336 | { | |
337 | errno = ENOSYS; | |
338 | error_setg_errno(errp, errno, | |
339 | "cannot fork child process"); | |
340 | return -1; | |
341 | } | |
a2d96af4 DB |
342 | |
343 | ||
344 | #undef connect | |
345 | int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, | |
346 | socklen_t addrlen) | |
347 | { | |
348 | int ret; | |
349 | ret = connect(sockfd, addr, addrlen); | |
350 | if (ret < 0) { | |
f1cd5d41 MAL |
351 | if (WSAGetLastError() == WSAEWOULDBLOCK) { |
352 | errno = EINPROGRESS; | |
353 | } else { | |
354 | errno = socket_error(); | |
355 | } | |
a2d96af4 DB |
356 | } |
357 | return ret; | |
358 | } | |
359 | ||
360 | ||
361 | #undef listen | |
362 | int qemu_listen_wrap(int sockfd, int backlog) | |
363 | { | |
364 | int ret; | |
365 | ret = listen(sockfd, backlog); | |
366 | if (ret < 0) { | |
367 | errno = socket_error(); | |
368 | } | |
369 | return ret; | |
370 | } | |
371 | ||
372 | ||
373 | #undef bind | |
374 | int qemu_bind_wrap(int sockfd, const struct sockaddr *addr, | |
375 | socklen_t addrlen) | |
376 | { | |
377 | int ret; | |
378 | ret = bind(sockfd, addr, addrlen); | |
379 | if (ret < 0) { | |
380 | errno = socket_error(); | |
381 | } | |
382 | return ret; | |
383 | } | |
384 | ||
385 | ||
386 | #undef socket | |
387 | int qemu_socket_wrap(int domain, int type, int protocol) | |
388 | { | |
389 | int ret; | |
390 | ret = socket(domain, type, protocol); | |
391 | if (ret < 0) { | |
392 | errno = socket_error(); | |
393 | } | |
394 | return ret; | |
395 | } | |
396 | ||
397 | ||
398 | #undef accept | |
399 | int qemu_accept_wrap(int sockfd, struct sockaddr *addr, | |
400 | socklen_t *addrlen) | |
401 | { | |
402 | int ret; | |
403 | ret = accept(sockfd, addr, addrlen); | |
404 | if (ret < 0) { | |
405 | errno = socket_error(); | |
406 | } | |
407 | return ret; | |
408 | } | |
409 | ||
410 | ||
411 | #undef shutdown | |
412 | int qemu_shutdown_wrap(int sockfd, int how) | |
413 | { | |
414 | int ret; | |
415 | ret = shutdown(sockfd, how); | |
416 | if (ret < 0) { | |
417 | errno = socket_error(); | |
418 | } | |
419 | return ret; | |
420 | } | |
421 | ||
422 | ||
423 | #undef ioctlsocket | |
424 | int qemu_ioctlsocket_wrap(int fd, int req, void *val) | |
425 | { | |
426 | int ret; | |
427 | ret = ioctlsocket(fd, req, val); | |
428 | if (ret < 0) { | |
429 | errno = socket_error(); | |
430 | } | |
431 | return ret; | |
432 | } | |
433 | ||
434 | ||
435 | #undef closesocket | |
436 | int qemu_closesocket_wrap(int fd) | |
437 | { | |
438 | int ret; | |
439 | ret = closesocket(fd); | |
440 | if (ret < 0) { | |
441 | errno = socket_error(); | |
442 | } | |
443 | return ret; | |
444 | } | |
445 | ||
446 | ||
447 | #undef getsockopt | |
448 | int qemu_getsockopt_wrap(int sockfd, int level, int optname, | |
449 | void *optval, socklen_t *optlen) | |
450 | { | |
451 | int ret; | |
452 | ret = getsockopt(sockfd, level, optname, optval, optlen); | |
453 | if (ret < 0) { | |
454 | errno = socket_error(); | |
455 | } | |
456 | return ret; | |
457 | } | |
458 | ||
459 | ||
460 | #undef setsockopt | |
461 | int qemu_setsockopt_wrap(int sockfd, int level, int optname, | |
462 | const void *optval, socklen_t optlen) | |
463 | { | |
464 | int ret; | |
465 | ret = setsockopt(sockfd, level, optname, optval, optlen); | |
466 | if (ret < 0) { | |
467 | errno = socket_error(); | |
468 | } | |
469 | return ret; | |
470 | } | |
471 | ||
472 | ||
473 | #undef getpeername | |
474 | int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr, | |
475 | socklen_t *addrlen) | |
476 | { | |
477 | int ret; | |
478 | ret = getpeername(sockfd, addr, addrlen); | |
479 | if (ret < 0) { | |
480 | errno = socket_error(); | |
481 | } | |
482 | return ret; | |
483 | } | |
484 | ||
485 | ||
486 | #undef getsockname | |
487 | int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr, | |
488 | socklen_t *addrlen) | |
489 | { | |
490 | int ret; | |
491 | ret = getsockname(sockfd, addr, addrlen); | |
492 | if (ret < 0) { | |
493 | errno = socket_error(); | |
494 | } | |
495 | return ret; | |
496 | } | |
497 | ||
498 | ||
499 | #undef send | |
500 | ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags) | |
501 | { | |
502 | int ret; | |
503 | ret = send(sockfd, buf, len, flags); | |
504 | if (ret < 0) { | |
505 | errno = socket_error(); | |
506 | } | |
507 | return ret; | |
508 | } | |
509 | ||
510 | ||
511 | #undef sendto | |
512 | ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags, | |
513 | const struct sockaddr *addr, socklen_t addrlen) | |
514 | { | |
515 | int ret; | |
516 | ret = sendto(sockfd, buf, len, flags, addr, addrlen); | |
517 | if (ret < 0) { | |
518 | errno = socket_error(); | |
519 | } | |
520 | return ret; | |
521 | } | |
522 | ||
523 | ||
524 | #undef recv | |
525 | ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags) | |
526 | { | |
527 | int ret; | |
528 | ret = recv(sockfd, buf, len, flags); | |
529 | if (ret < 0) { | |
530 | errno = socket_error(); | |
531 | } | |
532 | return ret; | |
533 | } | |
534 | ||
535 | ||
536 | #undef recvfrom | |
537 | ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, | |
538 | struct sockaddr *addr, socklen_t *addrlen) | |
539 | { | |
540 | int ret; | |
541 | ret = recvfrom(sockfd, buf, len, flags, addr, addrlen); | |
542 | if (ret < 0) { | |
543 | errno = socket_error(); | |
544 | } | |
545 | return ret; | |
546 | } | |
9e6bdef2 MAL |
547 | |
548 | bool qemu_write_pidfile(const char *filename, Error **errp) | |
549 | { | |
550 | char buffer[128]; | |
551 | int len; | |
552 | HANDLE file; | |
553 | OVERLAPPED overlap; | |
554 | BOOL ret; | |
555 | memset(&overlap, 0, sizeof(overlap)); | |
556 | ||
557 | file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, | |
558 | OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
559 | ||
560 | if (file == INVALID_HANDLE_VALUE) { | |
561 | error_setg(errp, "Failed to create PID file"); | |
562 | return false; | |
563 | } | |
564 | len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", (pid_t)getpid()); | |
565 | ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len, | |
566 | NULL, &overlap); | |
567 | CloseHandle(file); | |
568 | if (ret == 0) { | |
569 | error_setg(errp, "Failed to write PID file"); | |
570 | return false; | |
571 | } | |
572 | return true; | |
573 | } | |
e47f4765 | 574 | |
ad06ef0e AB |
575 | size_t qemu_get_host_physmem(void) |
576 | { | |
986babaa AB |
577 | MEMORYSTATUSEX statex; |
578 | statex.dwLength = sizeof(statex); | |
579 | ||
580 | if (GlobalMemoryStatusEx(&statex)) { | |
581 | return statex.ullTotalPhys; | |
582 | } | |
ad06ef0e AB |
583 | return 0; |
584 | } | |
73991a92 MAL |
585 | |
586 | int qemu_msync(void *addr, size_t length, int fd) | |
587 | { | |
588 | /** | |
589 | * Perform the sync based on the file descriptor | |
590 | * The sync range will most probably be wider than the one | |
591 | * requested - but it will still get the job done | |
592 | */ | |
593 | return qemu_fdatasync(fd); | |
594 | } |