xref: /openbmc/qemu/util/oslib-win32.c (revision bd6aa0d1e59d71218c3eee055bc8d222c6e1a628)
1 /*
2  * os-win32.c
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  * Copyright (c) 2010-2016 Red Hat, Inc.
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.
27  */
28 
29 #include "qemu/osdep.h"
30 #include <windows.h>
31 #include "qapi/error.h"
32 #include "qemu/main-loop.h"
33 #include "trace.h"
34 #include "qemu/sockets.h"
35 #include "qemu/cutils.h"
36 #include "qemu/error-report.h"
37 #include <malloc.h>
38 
39 static int get_allocation_granularity(void)
40 {
41     SYSTEM_INFO system_info;
42 
43     GetSystemInfo(&system_info);
44     return system_info.dwAllocationGranularity;
45 }
46 
47 void *qemu_anon_ram_alloc(size_t size, uint64_t *align, bool shared,
48                           bool noreserve)
49 {
50     void *ptr;
51 
52     if (noreserve) {
53         /*
54          * We need a MEM_COMMIT before accessing any memory in a MEM_RESERVE
55          * area; we cannot easily mimic POSIX MAP_NORESERVE semantics.
56          */
57         error_report("Skipping reservation of swap space is not supported.");
58         return NULL;
59     }
60 
61     ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
62     trace_qemu_anon_ram_alloc(size, ptr);
63 
64     if (ptr && align) {
65         *align = MAX(get_allocation_granularity(), getpagesize());
66     }
67     return ptr;
68 }
69 
70 void qemu_anon_ram_free(void *ptr, size_t size)
71 {
72     trace_qemu_anon_ram_free(ptr, size);
73     if (ptr) {
74         VirtualFree(ptr, 0, MEM_RELEASE);
75     }
76 }
77 
78 #ifndef _POSIX_THREAD_SAFE_FUNCTIONS
79 /* FIXME: add proper locking */
80 struct tm *gmtime_r(const time_t *timep, struct tm *result)
81 {
82     struct tm *p = gmtime(timep);
83     memset(result, 0, sizeof(*result));
84     if (p) {
85         *result = *p;
86         p = result;
87     }
88     return p;
89 }
90 
91 /* FIXME: add proper locking */
92 struct tm *localtime_r(const time_t *timep, struct tm *result)
93 {
94     struct tm *p = localtime(timep);
95     memset(result, 0, sizeof(*result));
96     if (p) {
97         *result = *p;
98         p = result;
99     }
100     return p;
101 }
102 #endif /* _POSIX_THREAD_SAFE_FUNCTIONS */
103 
104 static int socket_error(void)
105 {
106     switch (WSAGetLastError()) {
107     case 0:
108         return 0;
109     case WSAEINTR:
110         return EINTR;
111     case WSAEINVAL:
112         return EINVAL;
113     case WSA_INVALID_HANDLE:
114         return EBADF;
115     case WSA_NOT_ENOUGH_MEMORY:
116         return ENOMEM;
117     case WSA_INVALID_PARAMETER:
118         return EINVAL;
119     case WSAENAMETOOLONG:
120         return ENAMETOOLONG;
121     case WSAENOTEMPTY:
122         return ENOTEMPTY;
123     case WSAEWOULDBLOCK:
124          /* not using EWOULDBLOCK as we don't want code to have
125           * to check both EWOULDBLOCK and EAGAIN */
126         return EAGAIN;
127     case WSAEINPROGRESS:
128         return EINPROGRESS;
129     case WSAEALREADY:
130         return EALREADY;
131     case WSAENOTSOCK:
132         return ENOTSOCK;
133     case WSAEDESTADDRREQ:
134         return EDESTADDRREQ;
135     case WSAEMSGSIZE:
136         return EMSGSIZE;
137     case WSAEPROTOTYPE:
138         return EPROTOTYPE;
139     case WSAENOPROTOOPT:
140         return ENOPROTOOPT;
141     case WSAEPROTONOSUPPORT:
142         return EPROTONOSUPPORT;
143     case WSAEOPNOTSUPP:
144         return EOPNOTSUPP;
145     case WSAEAFNOSUPPORT:
146         return EAFNOSUPPORT;
147     case WSAEADDRINUSE:
148         return EADDRINUSE;
149     case WSAEADDRNOTAVAIL:
150         return EADDRNOTAVAIL;
151     case WSAENETDOWN:
152         return ENETDOWN;
153     case WSAENETUNREACH:
154         return ENETUNREACH;
155     case WSAENETRESET:
156         return ENETRESET;
157     case WSAECONNABORTED:
158         return ECONNABORTED;
159     case WSAECONNRESET:
160         return ECONNRESET;
161     case WSAENOBUFS:
162         return ENOBUFS;
163     case WSAEISCONN:
164         return EISCONN;
165     case WSAENOTCONN:
166         return ENOTCONN;
167     case WSAETIMEDOUT:
168         return ETIMEDOUT;
169     case WSAECONNREFUSED:
170         return ECONNREFUSED;
171     case WSAELOOP:
172         return ELOOP;
173     case WSAEHOSTUNREACH:
174         return EHOSTUNREACH;
175     default:
176         return EIO;
177     }
178 }
179 
180 bool qemu_set_blocking(int fd, bool block, Error **errp)
181 {
182     unsigned long opt = block ? 0 : 1;
183 
184     if (block) {
185         qemu_socket_unselect_nofail(fd);
186     }
187 
188     if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) {
189         error_setg_errno(errp, socket_error(),
190                          "Can't set file descriptor %d %s", fd,
191                          block ? "blocking" : "non-blocking");
192         return false;
193     }
194 
195     return true;
196 }
197 
198 int socket_set_fast_reuse(int fd)
199 {
200     /* Enabling the reuse of an endpoint that was used by a socket still in
201      * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
202      * fast reuse is the default and SO_REUSEADDR does strange things. So we
203      * don't have to do anything here. More info can be found at:
204      * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
205     return 0;
206 }
207 
208 int inet_aton(const char *cp, struct in_addr *ia)
209 {
210     uint32_t addr = inet_addr(cp);
211     if (addr == 0xffffffff) {
212         return 0;
213     }
214     ia->s_addr = addr;
215     return 1;
216 }
217 
218 void qemu_set_cloexec(int fd)
219 {
220 }
221 
222 void qemu_clear_cloexec(int fd)
223 {
224 }
225 
226 int qemu_get_thread_id(void)
227 {
228     return GetCurrentThreadId();
229 }
230 
231 char *
232 qemu_get_local_state_dir(void)
233 {
234     const char * const *data_dirs = g_get_system_data_dirs();
235 
236     g_assert(data_dirs && data_dirs[0]);
237 
238     return g_strdup(data_dirs[0]);
239 }
240 
241 void qemu_set_tty_echo(int fd, bool echo)
242 {
243     HANDLE handle = (HANDLE)_get_osfhandle(fd);
244     DWORD dwMode = 0;
245 
246     if (handle == INVALID_HANDLE_VALUE) {
247         return;
248     }
249 
250     GetConsoleMode(handle, &dwMode);
251 
252     if (echo) {
253         SetConsoleMode(handle, dwMode | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
254     } else {
255         SetConsoleMode(handle,
256                        dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
257     }
258 }
259 
260 int getpagesize(void)
261 {
262     SYSTEM_INFO system_info;
263 
264     GetSystemInfo(&system_info);
265     return system_info.dwPageSize;
266 }
267 
268 bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
269                        ThreadContext *tc, bool async, Error **errp)
270 {
271     int i;
272     size_t pagesize = qemu_real_host_page_size();
273 
274     sz = (sz + pagesize - 1) & -pagesize;
275     for (i = 0; i < sz / pagesize; i++) {
276         memset(area + pagesize * i, 0, 1);
277     }
278 
279     return true;
280 }
281 
282 bool qemu_finish_async_prealloc_mem(Error **errp)
283 {
284     /* async prealloc not supported, there is nothing to finish */
285     return true;
286 }
287 
288 char *qemu_get_pid_name(pid_t pid)
289 {
290     /* XXX Implement me */
291     abort();
292 }
293 
294 
295 bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
296                         long lNetworkEvents, Error **errp)
297 {
298     SOCKET s = _get_osfhandle(sockfd);
299 
300     if (s == INVALID_SOCKET) {
301         error_setg(errp, "invalid socket fd=%d", sockfd);
302         return false;
303     }
304 
305     if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) {
306         error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()");
307         return false;
308     }
309 
310     return true;
311 }
312 
313 bool qemu_socket_unselect(int sockfd, Error **errp)
314 {
315     return qemu_socket_select(sockfd, NULL, 0, errp);
316 }
317 
318 void qemu_socket_select_nofail(int sockfd, WSAEVENT hEventObject,
319                                long lNetworkEvents)
320 {
321     Error *err = NULL;
322 
323     if (!qemu_socket_select(sockfd, hEventObject, lNetworkEvents, &err)) {
324         warn_report_err(err);
325     }
326 }
327 
328 void qemu_socket_unselect_nofail(int sockfd)
329 {
330     Error *err = NULL;
331 
332     if (!qemu_socket_unselect(sockfd, &err)) {
333         warn_report_err(err);
334     }
335 }
336 
337 int qemu_socketpair(int domain, int type, int protocol, int sv[2])
338 {
339     struct sockaddr_un addr = {
340         0,
341     };
342     socklen_t socklen;
343     int listener = -1;
344     int client = -1;
345     int server = -1;
346     g_autofree char *path = NULL;
347     int tmpfd;
348     u_long arg;
349     int ret = -1;
350 
351     g_return_val_if_fail(sv != NULL, -1);
352 
353     addr.sun_family = AF_UNIX;
354     socklen = sizeof(addr);
355 
356     tmpfd = g_file_open_tmp(NULL, &path, NULL);
357     if (tmpfd == -1 || !path) {
358         errno = EACCES;
359         goto out;
360     }
361 
362     close(tmpfd);
363 
364     if (strlen(path) >= sizeof(addr.sun_path)) {
365         errno = EINVAL;
366         goto out;
367     }
368 
369     strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
370 
371     listener = socket(domain, type, protocol);
372     if (listener == -1) {
373         goto out;
374     }
375 
376     if (DeleteFile(path) == 0 && GetLastError() != ERROR_FILE_NOT_FOUND) {
377         errno = EACCES;
378         goto out;
379     }
380     g_clear_pointer(&path, g_free);
381 
382     if (bind(listener, (struct sockaddr *)&addr, socklen) == -1) {
383         goto out;
384     }
385 
386     if (listen(listener, 1) == -1) {
387         goto out;
388     }
389 
390     client = socket(domain, type, protocol);
391     if (client == -1) {
392         goto out;
393     }
394 
395     arg = 1;
396     if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
397         goto out;
398     }
399 
400     if (connect(client, (struct sockaddr *)&addr, socklen) == -1 &&
401         WSAGetLastError() != WSAEWOULDBLOCK) {
402         goto out;
403     }
404 
405     server = accept(listener, NULL, NULL);
406     if (server == -1) {
407         goto out;
408     }
409 
410     arg = 0;
411     if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
412         goto out;
413     }
414 
415     arg = 0;
416     if (ioctlsocket(client, SIO_AF_UNIX_GETPEERPID, &arg) != NO_ERROR) {
417         goto out;
418     }
419 
420     if (arg != GetCurrentProcessId()) {
421         errno = EPERM;
422         goto out;
423     }
424 
425     sv[0] = server;
426     server = -1;
427     sv[1] = client;
428     client = -1;
429     ret = 0;
430 
431 out:
432     if (listener != -1) {
433         close(listener);
434     }
435     if (client != -1) {
436         close(client);
437     }
438     if (server != -1) {
439         close(server);
440     }
441     if (path) {
442         DeleteFile(path);
443     }
444     return ret;
445 }
446 
447 #undef connect
448 int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
449                       socklen_t addrlen)
450 {
451     int ret;
452     SOCKET s = _get_osfhandle(sockfd);
453 
454     if (s == INVALID_SOCKET) {
455         return -1;
456     }
457 
458     ret = connect(s, addr, addrlen);
459     if (ret < 0) {
460         if (WSAGetLastError() == WSAEWOULDBLOCK) {
461             errno = EINPROGRESS;
462         } else {
463             errno = socket_error();
464         }
465     }
466     return ret;
467 }
468 
469 
470 #undef listen
471 int qemu_listen_wrap(int sockfd, int backlog)
472 {
473     int ret;
474     SOCKET s = _get_osfhandle(sockfd);
475 
476     if (s == INVALID_SOCKET) {
477         return -1;
478     }
479 
480     ret = listen(s, backlog);
481     if (ret < 0) {
482         errno = socket_error();
483     }
484     return ret;
485 }
486 
487 
488 #undef bind
489 int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
490                    socklen_t addrlen)
491 {
492     int ret;
493     SOCKET s = _get_osfhandle(sockfd);
494 
495     if (s == INVALID_SOCKET) {
496         return -1;
497     }
498 
499     ret = bind(s, addr, addrlen);
500     if (ret < 0) {
501         errno = socket_error();
502     }
503     return ret;
504 }
505 
506 QEMU_USED EXCEPTION_DISPOSITION
507 win32_close_exception_handler(struct _EXCEPTION_RECORD *exception_record,
508                               void *registration, struct _CONTEXT *context,
509                               void *dispatcher)
510 {
511     return EXCEPTION_EXECUTE_HANDLER;
512 }
513 
514 #undef close
515 int qemu_close_socket_osfhandle(int fd)
516 {
517     SOCKET s = _get_osfhandle(fd);
518     DWORD flags = 0;
519 
520     /*
521      * If we were to just call _close on the descriptor, it would close the
522      * HANDLE, but it wouldn't free any of the resources associated to the
523      * SOCKET, and we can't call _close after calling closesocket, because
524      * closesocket has already closed the HANDLE, and _close would attempt to
525      * close the HANDLE again, resulting in a double free. We can however
526      * protect the HANDLE from actually being closed long enough to close the
527      * file descriptor, then close the socket itself.
528      */
529     if (!GetHandleInformation((HANDLE)s, &flags)) {
530         errno = EACCES;
531         return -1;
532     }
533 
534     if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
535         errno = EACCES;
536         return -1;
537     }
538 
539     __try1(win32_close_exception_handler) {
540         /*
541          * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying
542          * handle, but the FD is actually freed
543          */
544         if (close(fd) < 0 && errno != EBADF) {
545             return -1;
546         }
547     }
548     __except1 {
549     }
550 
551     if (!SetHandleInformation((HANDLE)s, flags, flags)) {
552         errno = EACCES;
553         return -1;
554     }
555 
556     return 0;
557 }
558 
559 int qemu_close_wrap(int fd)
560 {
561     SOCKET s = INVALID_SOCKET;
562     int ret = -1;
563 
564     if (!fd_is_socket(fd)) {
565         return close(fd);
566     }
567 
568     s = _get_osfhandle(fd);
569     qemu_close_socket_osfhandle(fd);
570 
571     ret = closesocket(s);
572     if (ret < 0) {
573         errno = socket_error();
574     }
575 
576     return ret;
577 }
578 
579 
580 #undef socket
581 int qemu_socket_wrap(int domain, int type, int protocol)
582 {
583     SOCKET s;
584     int fd;
585 
586     s = socket(domain, type, protocol);
587     if (s == -1) {
588         errno = socket_error();
589         return -1;
590     }
591 
592     fd = _open_osfhandle(s, _O_BINARY);
593     if (fd < 0) {
594         closesocket(s);
595         /* _open_osfhandle may not set errno, and closesocket() may override it */
596         errno = ENOMEM;
597     }
598 
599     return fd;
600 }
601 
602 
603 #undef accept
604 int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
605                      socklen_t *addrlen)
606 {
607     int fd;
608     SOCKET s = _get_osfhandle(sockfd);
609 
610     if (s == INVALID_SOCKET) {
611         return -1;
612     }
613 
614     s = accept(s, addr, addrlen);
615     if (s == -1) {
616         errno = socket_error();
617         return -1;
618     }
619 
620     fd = _open_osfhandle(s, _O_BINARY);
621     if (fd < 0) {
622         closesocket(s);
623         /* _open_osfhandle may not set errno, and closesocket() may override it */
624         errno = ENOMEM;
625     }
626 
627     return fd;
628 }
629 
630 
631 #undef shutdown
632 int qemu_shutdown_wrap(int sockfd, int how)
633 {
634     int ret;
635     SOCKET s = _get_osfhandle(sockfd);
636 
637     if (s == INVALID_SOCKET) {
638         return -1;
639     }
640 
641     ret = shutdown(s, how);
642     if (ret < 0) {
643         errno = socket_error();
644     }
645     return ret;
646 }
647 
648 
649 #undef ioctlsocket
650 int qemu_ioctlsocket_wrap(int fd, int req, void *val)
651 {
652     int ret;
653     SOCKET s = _get_osfhandle(fd);
654 
655     if (s == INVALID_SOCKET) {
656         return -1;
657     }
658 
659     ret = ioctlsocket(s, req, val);
660     if (ret < 0) {
661         errno = socket_error();
662     }
663     return ret;
664 }
665 
666 
667 #undef getsockopt
668 int qemu_getsockopt_wrap(int sockfd, int level, int optname,
669                          void *optval, socklen_t *optlen)
670 {
671     int ret;
672     SOCKET s = _get_osfhandle(sockfd);
673 
674     if (s == INVALID_SOCKET) {
675         return -1;
676     }
677 
678     ret = getsockopt(s, level, optname, optval, optlen);
679     if (ret < 0) {
680         errno = socket_error();
681     }
682     return ret;
683 }
684 
685 
686 #undef setsockopt
687 int qemu_setsockopt_wrap(int sockfd, int level, int optname,
688                          const void *optval, socklen_t optlen)
689 {
690     int ret;
691     SOCKET s = _get_osfhandle(sockfd);
692 
693     if (s == INVALID_SOCKET) {
694         return -1;
695     }
696 
697     ret = setsockopt(s, level, optname, optval, optlen);
698     if (ret < 0) {
699         errno = socket_error();
700     }
701     return ret;
702 }
703 
704 
705 #undef getpeername
706 int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
707                           socklen_t *addrlen)
708 {
709     int ret;
710     SOCKET s = _get_osfhandle(sockfd);
711 
712     if (s == INVALID_SOCKET) {
713         return -1;
714     }
715 
716     ret = getpeername(s, addr, addrlen);
717     if (ret < 0) {
718         errno = socket_error();
719     }
720     return ret;
721 }
722 
723 
724 #undef getsockname
725 int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
726                           socklen_t *addrlen)
727 {
728     int ret;
729     SOCKET s = _get_osfhandle(sockfd);
730 
731     if (s == INVALID_SOCKET) {
732         return -1;
733     }
734 
735     ret = getsockname(s, addr, addrlen);
736     if (ret < 0) {
737         errno = socket_error();
738     }
739     return ret;
740 }
741 
742 
743 #undef send
744 ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
745 {
746     int ret;
747     SOCKET s = _get_osfhandle(sockfd);
748 
749     if (s == INVALID_SOCKET) {
750         return -1;
751     }
752 
753     ret = send(s, buf, len, flags);
754     if (ret < 0) {
755         errno = socket_error();
756     }
757     return ret;
758 }
759 
760 
761 #undef sendto
762 ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
763                          const struct sockaddr *addr, socklen_t addrlen)
764 {
765     int ret;
766     SOCKET s = _get_osfhandle(sockfd);
767 
768     if (s == INVALID_SOCKET) {
769         return -1;
770     }
771 
772     ret = sendto(s, buf, len, flags, addr, addrlen);
773     if (ret < 0) {
774         errno = socket_error();
775     }
776     return ret;
777 }
778 
779 
780 #undef recv
781 ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
782 {
783     int ret;
784     SOCKET s = _get_osfhandle(sockfd);
785 
786     if (s == INVALID_SOCKET) {
787         return -1;
788     }
789 
790     ret = recv(s, buf, len, flags);
791     if (ret < 0) {
792         errno = socket_error();
793     }
794     return ret;
795 }
796 
797 
798 #undef recvfrom
799 ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
800                            struct sockaddr *addr, socklen_t *addrlen)
801 {
802     int ret;
803     SOCKET s = _get_osfhandle(sockfd);
804 
805     if (s == INVALID_SOCKET) {
806         return -1;
807     }
808 
809     ret = recvfrom(s, buf, len, flags, addr, addrlen);
810     if (ret < 0) {
811         errno = socket_error();
812     }
813     return ret;
814 }
815 
816 bool qemu_write_pidfile(const char *filename, Error **errp)
817 {
818     char buffer[128];
819     int len;
820     HANDLE file;
821     OVERLAPPED overlap;
822     BOOL ret;
823     memset(&overlap, 0, sizeof(overlap));
824 
825     file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
826                       OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
827 
828     if (file == INVALID_HANDLE_VALUE) {
829         error_setg(errp, "Failed to create PID file");
830         return false;
831     }
832     len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", (pid_t)getpid());
833     ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len,
834                     NULL, &overlap);
835     CloseHandle(file);
836     if (ret == 0) {
837         error_setg(errp, "Failed to write PID file");
838         return false;
839     }
840     return true;
841 }
842 
843 size_t qemu_get_host_physmem(void)
844 {
845     MEMORYSTATUSEX statex;
846     statex.dwLength = sizeof(statex);
847 
848     if (GlobalMemoryStatusEx(&statex)) {
849         return statex.ullTotalPhys;
850     }
851     return 0;
852 }
853 
854 int qemu_msync(void *addr, size_t length, int fd)
855 {
856     /**
857      * Perform the sync based on the file descriptor
858      * The sync range will most probably be wider than the one
859      * requested - but it will still get the job done
860      */
861     return qemu_fdatasync(fd);
862 }
863 
864 void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp)
865 {
866     void *bits;
867 
868     trace_win32_map_alloc(size);
869 
870     *h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
871                           size, NULL);
872     if (*h == NULL) {
873         error_setg_win32(errp, GetLastError(), "Failed to CreateFileMapping");
874         return NULL;
875     }
876 
877     bits = MapViewOfFile(*h, FILE_MAP_ALL_ACCESS, 0, 0, size);
878     if (bits == NULL) {
879         error_setg_win32(errp, GetLastError(), "Failed to MapViewOfFile");
880         CloseHandle(*h);
881         return NULL;
882     }
883 
884     return bits;
885 }
886 
887 void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp)
888 {
889     trace_win32_map_free(ptr, h);
890 
891     if (UnmapViewOfFile(ptr) == 0) {
892         error_setg_win32(errp, GetLastError(), "Failed to UnmapViewOfFile");
893     }
894     CloseHandle(h);
895 }
896 
897 int qemu_shm_alloc(size_t size, Error **errp)
898 {
899     error_setg(errp, "Shared memory is not supported.");
900     return -1;
901 }
902