qemu/util/oslib-win32.c
<<
>>
Prefs
   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
  39static int get_allocation_granularity(void)
  40{
  41    SYSTEM_INFO system_info;
  42
  43    GetSystemInfo(&system_info);
  44    return system_info.dwAllocationGranularity;
  45}
  46
  47void *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
  70void 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 */
  80struct 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 */
  92struct 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
 104static 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
 180void qemu_socket_set_block(int fd)
 181{
 182    unsigned long opt = 0;
 183    qemu_socket_unselect(fd, NULL);
 184    ioctlsocket(fd, FIONBIO, &opt);
 185}
 186
 187int qemu_socket_try_set_nonblock(int fd)
 188{
 189    unsigned long opt = 1;
 190    if (ioctlsocket(fd, FIONBIO, &opt) != NO_ERROR) {
 191        return -socket_error();
 192    }
 193    return 0;
 194}
 195
 196void qemu_socket_set_nonblock(int fd)
 197{
 198    (void)qemu_socket_try_set_nonblock(fd);
 199}
 200
 201int socket_set_fast_reuse(int fd)
 202{
 203    /* Enabling the reuse of an endpoint that was used by a socket still in
 204     * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
 205     * fast reuse is the default and SO_REUSEADDR does strange things. So we
 206     * don't have to do anything here. More info can be found at:
 207     * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
 208    return 0;
 209}
 210
 211int inet_aton(const char *cp, struct in_addr *ia)
 212{
 213    uint32_t addr = inet_addr(cp);
 214    if (addr == 0xffffffff) {
 215        return 0;
 216    }
 217    ia->s_addr = addr;
 218    return 1;
 219}
 220
 221void qemu_set_cloexec(int fd)
 222{
 223}
 224
 225int qemu_get_thread_id(void)
 226{
 227    return GetCurrentThreadId();
 228}
 229
 230char *
 231qemu_get_local_state_dir(void)
 232{
 233    const char * const *data_dirs = g_get_system_data_dirs();
 234
 235    g_assert(data_dirs && data_dirs[0]);
 236
 237    return g_strdup(data_dirs[0]);
 238}
 239
 240void qemu_set_tty_echo(int fd, bool echo)
 241{
 242    HANDLE handle = (HANDLE)_get_osfhandle(fd);
 243    DWORD dwMode = 0;
 244
 245    if (handle == INVALID_HANDLE_VALUE) {
 246        return;
 247    }
 248
 249    GetConsoleMode(handle, &dwMode);
 250
 251    if (echo) {
 252        SetConsoleMode(handle, dwMode | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
 253    } else {
 254        SetConsoleMode(handle,
 255                       dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
 256    }
 257}
 258
 259int getpagesize(void)
 260{
 261    SYSTEM_INFO system_info;
 262
 263    GetSystemInfo(&system_info);
 264    return system_info.dwPageSize;
 265}
 266
 267void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
 268                       ThreadContext *tc, Error **errp)
 269{
 270    int i;
 271    size_t pagesize = qemu_real_host_page_size();
 272
 273    sz = (sz + pagesize - 1) & -pagesize;
 274    for (i = 0; i < sz / pagesize; i++) {
 275        memset(area + pagesize * i, 0, 1);
 276    }
 277}
 278
 279char *qemu_get_pid_name(pid_t pid)
 280{
 281    /* XXX Implement me */
 282    abort();
 283}
 284
 285
 286bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
 287                        long lNetworkEvents, Error **errp)
 288{
 289    SOCKET s = _get_osfhandle(sockfd);
 290
 291    if (errp == NULL) {
 292        errp = &error_warn;
 293    }
 294
 295    if (s == INVALID_SOCKET) {
 296        error_setg(errp, "invalid socket fd=%d", sockfd);
 297        return false;
 298    }
 299
 300    if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) {
 301        error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()");
 302        return false;
 303    }
 304
 305    return true;
 306}
 307
 308bool qemu_socket_unselect(int sockfd, Error **errp)
 309{
 310    return qemu_socket_select(sockfd, NULL, 0, errp);
 311}
 312
 313int qemu_socketpair(int domain, int type, int protocol, int sv[2])
 314{
 315    struct sockaddr_un addr = {
 316        0,
 317    };
 318    socklen_t socklen;
 319    int listener = -1;
 320    int client = -1;
 321    int server = -1;
 322    g_autofree char *path = NULL;
 323    int tmpfd;
 324    u_long arg;
 325    int ret = -1;
 326
 327    g_return_val_if_fail(sv != NULL, -1);
 328
 329    addr.sun_family = AF_UNIX;
 330    socklen = sizeof(addr);
 331
 332    tmpfd = g_file_open_tmp(NULL, &path, NULL);
 333    if (tmpfd == -1 || !path) {
 334        errno = EACCES;
 335        goto out;
 336    }
 337
 338    close(tmpfd);
 339
 340    if (strlen(path) >= sizeof(addr.sun_path)) {
 341        errno = EINVAL;
 342        goto out;
 343    }
 344
 345    strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
 346
 347    listener = socket(domain, type, protocol);
 348    if (listener == -1) {
 349        goto out;
 350    }
 351
 352    if (DeleteFile(path) == 0 && GetLastError() != ERROR_FILE_NOT_FOUND) {
 353        errno = EACCES;
 354        goto out;
 355    }
 356    g_clear_pointer(&path, g_free);
 357
 358    if (bind(listener, (struct sockaddr *)&addr, socklen) == -1) {
 359        goto out;
 360    }
 361
 362    if (listen(listener, 1) == -1) {
 363        goto out;
 364    }
 365
 366    client = socket(domain, type, protocol);
 367    if (client == -1) {
 368        goto out;
 369    }
 370
 371    arg = 1;
 372    if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
 373        goto out;
 374    }
 375
 376    if (connect(client, (struct sockaddr *)&addr, socklen) == -1 &&
 377        WSAGetLastError() != WSAEWOULDBLOCK) {
 378        goto out;
 379    }
 380
 381    server = accept(listener, NULL, NULL);
 382    if (server == -1) {
 383        goto out;
 384    }
 385
 386    arg = 0;
 387    if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
 388        goto out;
 389    }
 390
 391    arg = 0;
 392    if (ioctlsocket(client, SIO_AF_UNIX_GETPEERPID, &arg) != NO_ERROR) {
 393        goto out;
 394    }
 395
 396    if (arg != GetCurrentProcessId()) {
 397        errno = EPERM;
 398        goto out;
 399    }
 400
 401    sv[0] = server;
 402    server = -1;
 403    sv[1] = client;
 404    client = -1;
 405    ret = 0;
 406
 407out:
 408    if (listener != -1) {
 409        close(listener);
 410    }
 411    if (client != -1) {
 412        close(client);
 413    }
 414    if (server != -1) {
 415        close(server);
 416    }
 417    if (path) {
 418        DeleteFile(path);
 419    }
 420    return ret;
 421}
 422
 423#undef connect
 424int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
 425                      socklen_t addrlen)
 426{
 427    int ret;
 428    SOCKET s = _get_osfhandle(sockfd);
 429
 430    if (s == INVALID_SOCKET) {
 431        return -1;
 432    }
 433
 434    ret = connect(s, addr, addrlen);
 435    if (ret < 0) {
 436        if (WSAGetLastError() == WSAEWOULDBLOCK) {
 437            errno = EINPROGRESS;
 438        } else {
 439            errno = socket_error();
 440        }
 441    }
 442    return ret;
 443}
 444
 445
 446#undef listen
 447int qemu_listen_wrap(int sockfd, int backlog)
 448{
 449    int ret;
 450    SOCKET s = _get_osfhandle(sockfd);
 451
 452    if (s == INVALID_SOCKET) {
 453        return -1;
 454    }
 455
 456    ret = listen(s, backlog);
 457    if (ret < 0) {
 458        errno = socket_error();
 459    }
 460    return ret;
 461}
 462
 463
 464#undef bind
 465int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
 466                   socklen_t addrlen)
 467{
 468    int ret;
 469    SOCKET s = _get_osfhandle(sockfd);
 470
 471    if (s == INVALID_SOCKET) {
 472        return -1;
 473    }
 474
 475    ret = bind(s, addr, addrlen);
 476    if (ret < 0) {
 477        errno = socket_error();
 478    }
 479    return ret;
 480}
 481
 482#undef close
 483int qemu_close_socket_osfhandle(int fd)
 484{
 485    SOCKET s = _get_osfhandle(fd);
 486    DWORD flags = 0;
 487
 488    /*
 489     * If we were to just call _close on the descriptor, it would close the
 490     * HANDLE, but it wouldn't free any of the resources associated to the
 491     * SOCKET, and we can't call _close after calling closesocket, because
 492     * closesocket has already closed the HANDLE, and _close would attempt to
 493     * close the HANDLE again, resulting in a double free. We can however
 494     * protect the HANDLE from actually being closed long enough to close the
 495     * file descriptor, then close the socket itself.
 496     */
 497    if (!GetHandleInformation((HANDLE)s, &flags)) {
 498        errno = EACCES;
 499        return -1;
 500    }
 501
 502    if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
 503        errno = EACCES;
 504        return -1;
 505    }
 506
 507    /*
 508     * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle,
 509     * but the FD is actually freed
 510     */
 511    if (close(fd) < 0 && errno != EBADF) {
 512        return -1;
 513    }
 514
 515    if (!SetHandleInformation((HANDLE)s, flags, flags)) {
 516        errno = EACCES;
 517        return -1;
 518    }
 519
 520    return 0;
 521}
 522
 523int qemu_close_wrap(int fd)
 524{
 525    SOCKET s = INVALID_SOCKET;
 526    int ret = -1;
 527
 528    if (!fd_is_socket(fd)) {
 529        return close(fd);
 530    }
 531
 532    s = _get_osfhandle(fd);
 533    qemu_close_socket_osfhandle(fd);
 534
 535    ret = closesocket(s);
 536    if (ret < 0) {
 537        errno = socket_error();
 538    }
 539
 540    return ret;
 541}
 542
 543
 544#undef socket
 545int qemu_socket_wrap(int domain, int type, int protocol)
 546{
 547    SOCKET s;
 548    int fd;
 549
 550    s = socket(domain, type, protocol);
 551    if (s == -1) {
 552        errno = socket_error();
 553        return -1;
 554    }
 555
 556    fd = _open_osfhandle(s, _O_BINARY);
 557    if (fd < 0) {
 558        closesocket(s);
 559        /* _open_osfhandle may not set errno, and closesocket() may override it */
 560        errno = ENOMEM;
 561    }
 562
 563    return fd;
 564}
 565
 566
 567#undef accept
 568int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
 569                     socklen_t *addrlen)
 570{
 571    int fd;
 572    SOCKET s = _get_osfhandle(sockfd);
 573
 574    if (s == INVALID_SOCKET) {
 575        return -1;
 576    }
 577
 578    s = accept(s, addr, addrlen);
 579    if (s == -1) {
 580        errno = socket_error();
 581        return -1;
 582    }
 583
 584    fd = _open_osfhandle(s, _O_BINARY);
 585    if (fd < 0) {
 586        closesocket(s);
 587        /* _open_osfhandle may not set errno, and closesocket() may override it */
 588        errno = ENOMEM;
 589    }
 590
 591    return fd;
 592}
 593
 594
 595#undef shutdown
 596int qemu_shutdown_wrap(int sockfd, int how)
 597{
 598    int ret;
 599    SOCKET s = _get_osfhandle(sockfd);
 600
 601    if (s == INVALID_SOCKET) {
 602        return -1;
 603    }
 604
 605    ret = shutdown(s, how);
 606    if (ret < 0) {
 607        errno = socket_error();
 608    }
 609    return ret;
 610}
 611
 612
 613#undef ioctlsocket
 614int qemu_ioctlsocket_wrap(int fd, int req, void *val)
 615{
 616    int ret;
 617    SOCKET s = _get_osfhandle(fd);
 618
 619    if (s == INVALID_SOCKET) {
 620        return -1;
 621    }
 622
 623    ret = ioctlsocket(s, req, val);
 624    if (ret < 0) {
 625        errno = socket_error();
 626    }
 627    return ret;
 628}
 629
 630
 631#undef getsockopt
 632int qemu_getsockopt_wrap(int sockfd, int level, int optname,
 633                         void *optval, socklen_t *optlen)
 634{
 635    int ret;
 636    SOCKET s = _get_osfhandle(sockfd);
 637
 638    if (s == INVALID_SOCKET) {
 639        return -1;
 640    }
 641
 642    ret = getsockopt(s, level, optname, optval, optlen);
 643    if (ret < 0) {
 644        errno = socket_error();
 645    }
 646    return ret;
 647}
 648
 649
 650#undef setsockopt
 651int qemu_setsockopt_wrap(int sockfd, int level, int optname,
 652                         const void *optval, socklen_t optlen)
 653{
 654    int ret;
 655    SOCKET s = _get_osfhandle(sockfd);
 656
 657    if (s == INVALID_SOCKET) {
 658        return -1;
 659    }
 660
 661    ret = setsockopt(s, level, optname, optval, optlen);
 662    if (ret < 0) {
 663        errno = socket_error();
 664    }
 665    return ret;
 666}
 667
 668
 669#undef getpeername
 670int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
 671                          socklen_t *addrlen)
 672{
 673    int ret;
 674    SOCKET s = _get_osfhandle(sockfd);
 675
 676    if (s == INVALID_SOCKET) {
 677        return -1;
 678    }
 679
 680    ret = getpeername(s, addr, addrlen);
 681    if (ret < 0) {
 682        errno = socket_error();
 683    }
 684    return ret;
 685}
 686
 687
 688#undef getsockname
 689int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
 690                          socklen_t *addrlen)
 691{
 692    int ret;
 693    SOCKET s = _get_osfhandle(sockfd);
 694
 695    if (s == INVALID_SOCKET) {
 696        return -1;
 697    }
 698
 699    ret = getsockname(s, addr, addrlen);
 700    if (ret < 0) {
 701        errno = socket_error();
 702    }
 703    return ret;
 704}
 705
 706
 707#undef send
 708ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
 709{
 710    int ret;
 711    SOCKET s = _get_osfhandle(sockfd);
 712
 713    if (s == INVALID_SOCKET) {
 714        return -1;
 715    }
 716
 717    ret = send(s, buf, len, flags);
 718    if (ret < 0) {
 719        errno = socket_error();
 720    }
 721    return ret;
 722}
 723
 724
 725#undef sendto
 726ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
 727                         const struct sockaddr *addr, socklen_t addrlen)
 728{
 729    int ret;
 730    SOCKET s = _get_osfhandle(sockfd);
 731
 732    if (s == INVALID_SOCKET) {
 733        return -1;
 734    }
 735
 736    ret = sendto(s, buf, len, flags, addr, addrlen);
 737    if (ret < 0) {
 738        errno = socket_error();
 739    }
 740    return ret;
 741}
 742
 743
 744#undef recv
 745ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
 746{
 747    int ret;
 748    SOCKET s = _get_osfhandle(sockfd);
 749
 750    if (s == INVALID_SOCKET) {
 751        return -1;
 752    }
 753
 754    ret = recv(s, buf, len, flags);
 755    if (ret < 0) {
 756        errno = socket_error();
 757    }
 758    return ret;
 759}
 760
 761
 762#undef recvfrom
 763ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
 764                           struct sockaddr *addr, socklen_t *addrlen)
 765{
 766    int ret;
 767    SOCKET s = _get_osfhandle(sockfd);
 768
 769    if (s == INVALID_SOCKET) {
 770        return -1;
 771    }
 772
 773    ret = recvfrom(s, buf, len, flags, addr, addrlen);
 774    if (ret < 0) {
 775        errno = socket_error();
 776    }
 777    return ret;
 778}
 779
 780bool qemu_write_pidfile(const char *filename, Error **errp)
 781{
 782    char buffer[128];
 783    int len;
 784    HANDLE file;
 785    OVERLAPPED overlap;
 786    BOOL ret;
 787    memset(&overlap, 0, sizeof(overlap));
 788
 789    file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
 790                      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 791
 792    if (file == INVALID_HANDLE_VALUE) {
 793        error_setg(errp, "Failed to create PID file");
 794        return false;
 795    }
 796    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", (pid_t)getpid());
 797    ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len,
 798                    NULL, &overlap);
 799    CloseHandle(file);
 800    if (ret == 0) {
 801        error_setg(errp, "Failed to write PID file");
 802        return false;
 803    }
 804    return true;
 805}
 806
 807size_t qemu_get_host_physmem(void)
 808{
 809    MEMORYSTATUSEX statex;
 810    statex.dwLength = sizeof(statex);
 811
 812    if (GlobalMemoryStatusEx(&statex)) {
 813        return statex.ullTotalPhys;
 814    }
 815    return 0;
 816}
 817
 818int qemu_msync(void *addr, size_t length, int fd)
 819{
 820    /**
 821     * Perform the sync based on the file descriptor
 822     * The sync range will most probably be wider than the one
 823     * requested - but it will still get the job done
 824     */
 825    return qemu_fdatasync(fd);
 826}
 827