xref: /openbmc/qemu/util/oslib-posix.c (revision a1eaa628)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * os-posix-lib.c
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright (c) 2003-2008 Fabrice Bellard
5baacf047SPaolo Bonzini  * Copyright (c) 2010 Red Hat, Inc.
6baacf047SPaolo Bonzini  *
7baacf047SPaolo Bonzini  * QEMU library functions on POSIX which are shared between QEMU and
8baacf047SPaolo Bonzini  * the QEMU tools.
9baacf047SPaolo Bonzini  *
10baacf047SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
11baacf047SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
12baacf047SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
13baacf047SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14baacf047SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
15baacf047SPaolo Bonzini  * furnished to do so, subject to the following conditions:
16baacf047SPaolo Bonzini  *
17baacf047SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
18baacf047SPaolo Bonzini  * all copies or substantial portions of the Software.
19baacf047SPaolo Bonzini  *
20baacf047SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21baacf047SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22baacf047SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23baacf047SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24baacf047SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25baacf047SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26baacf047SPaolo Bonzini  * THE SOFTWARE.
27baacf047SPaolo Bonzini  */
28baacf047SPaolo Bonzini 
29aafd7584SPeter Maydell #include "qemu/osdep.h"
3013401ba0SStefan Hajnoczi #include <termios.h>
3113401ba0SStefan Hajnoczi 
32e2ea3515SLaszlo Ersek #include <glib/gprintf.h>
33e2ea3515SLaszlo Ersek 
34baacf047SPaolo Bonzini #include "sysemu/sysemu.h"
35baacf047SPaolo Bonzini #include "trace.h"
36da34e65cSMarkus Armbruster #include "qapi/error.h"
3729b838c0SDavid Hildenbrand #include "qemu/error-report.h"
38b85ea5faSPeter Maydell #include "qemu/madvise.h"
39baacf047SPaolo Bonzini #include "qemu/sockets.h"
40db725815SMarkus Armbruster #include "qemu/thread.h"
4110f5bff6SFam Zheng #include <libgen.h>
42f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
4389aec641SDavid Hildenbrand #include "qemu/units.h"
44e2de2c49SDavid Hildenbrand #include "qemu/thread-context.h"
45baacf047SPaolo Bonzini 
46baacf047SPaolo Bonzini #ifdef CONFIG_LINUX
47baacf047SPaolo Bonzini #include <sys/syscall.h>
48baacf047SPaolo Bonzini #endif
49baacf047SPaolo Bonzini 
5041975b26SAndreas Färber #ifdef __FreeBSD__
519548a891SDavid Carlier #include <sys/thr.h>
5206680b15SMarc-André Lureau #include <sys/user.h>
537dc9ae43SMichal Privoznik #include <libutil.h>
5441975b26SAndreas Färber #endif
5541975b26SAndreas Färber 
56094611b4SKamil Rytarowski #ifdef __NetBSD__
579548a891SDavid Carlier #include <lwp.h>
58094611b4SKamil Rytarowski #endif
59094611b4SKamil Rytarowski 
60a9c94277SMarkus Armbruster #include "qemu/mmap-alloc.h"
61794e8f30SMichael S. Tsirkin 
62dfd0dcc7SJitendra Kolhe #define MAX_MEM_PREALLOC_THREAD_COUNT 16
631e356fc1SJitendra Kolhe 
64dba50678SDavid Hildenbrand struct MemsetThread;
65dba50678SDavid Hildenbrand 
66dba50678SDavid Hildenbrand typedef struct MemsetContext {
67dba50678SDavid Hildenbrand     bool all_threads_created;
68dba50678SDavid Hildenbrand     bool any_thread_failed;
69dba50678SDavid Hildenbrand     struct MemsetThread *threads;
70dba50678SDavid Hildenbrand     int num_threads;
71dba50678SDavid Hildenbrand } MemsetContext;
72dba50678SDavid Hildenbrand 
731e356fc1SJitendra Kolhe struct MemsetThread {
741e356fc1SJitendra Kolhe     char *addr;
75e947d47dSStefan Weil     size_t numpages;
76e947d47dSStefan Weil     size_t hpagesize;
771e356fc1SJitendra Kolhe     QemuThread pgthread;
781e356fc1SJitendra Kolhe     sigjmp_buf env;
79dba50678SDavid Hildenbrand     MemsetContext *context;
801e356fc1SJitendra Kolhe };
811e356fc1SJitendra Kolhe typedef struct MemsetThread MemsetThread;
821e356fc1SJitendra Kolhe 
83dba50678SDavid Hildenbrand /* used by sigbus_handler() */
84dba50678SDavid Hildenbrand static MemsetContext *sigbus_memset_context;
8529b838c0SDavid Hildenbrand struct sigaction sigbus_oldact;
86a960d664SDavid Hildenbrand static QemuMutex sigbus_mutex;
871e356fc1SJitendra Kolhe 
88037fb5ebSbauerchen static QemuMutex page_mutex;
89037fb5ebSbauerchen static QemuCond page_cond;
90037fb5ebSbauerchen 
qemu_get_thread_id(void)91baacf047SPaolo Bonzini int qemu_get_thread_id(void)
92baacf047SPaolo Bonzini {
93baacf047SPaolo Bonzini #if defined(__linux__)
94baacf047SPaolo Bonzini     return syscall(SYS_gettid);
959548a891SDavid Carlier #elif defined(__FreeBSD__)
969548a891SDavid Carlier     /* thread id is up to INT_MAX */
979548a891SDavid Carlier     long tid;
989548a891SDavid Carlier     thr_self(&tid);
999548a891SDavid Carlier     return (int)tid;
1009548a891SDavid Carlier #elif defined(__NetBSD__)
1019548a891SDavid Carlier     return _lwp_self();
1028edbca51SDavid CARLIER #elif defined(__OpenBSD__)
1038edbca51SDavid CARLIER     return getthrid();
104baacf047SPaolo Bonzini #else
105baacf047SPaolo Bonzini     return getpid();
106baacf047SPaolo Bonzini #endif
107baacf047SPaolo Bonzini }
108baacf047SPaolo Bonzini 
qemu_daemon(int nochdir,int noclose)109baacf047SPaolo Bonzini int qemu_daemon(int nochdir, int noclose)
110baacf047SPaolo Bonzini {
111baacf047SPaolo Bonzini     return daemon(nochdir, noclose);
112baacf047SPaolo Bonzini }
113baacf047SPaolo Bonzini 
qemu_write_pidfile(const char * path,Error ** errp)1149e6bdef2SMarc-André Lureau bool qemu_write_pidfile(const char *path, Error **errp)
1159e6bdef2SMarc-André Lureau {
1169e6bdef2SMarc-André Lureau     int fd;
1179e6bdef2SMarc-André Lureau     char pidstr[32];
1189e6bdef2SMarc-André Lureau 
1199e6bdef2SMarc-André Lureau     while (1) {
1209e6bdef2SMarc-André Lureau         struct stat a, b;
12135f7f3fbSMarc-André Lureau         struct flock lock = {
12235f7f3fbSMarc-André Lureau             .l_type = F_WRLCK,
12335f7f3fbSMarc-André Lureau             .l_whence = SEEK_SET,
12435f7f3fbSMarc-André Lureau             .l_len = 0,
12535f7f3fbSMarc-André Lureau         };
1269e6bdef2SMarc-André Lureau 
1271b34d08fSMarc-André Lureau         fd = qemu_create(path, O_WRONLY, S_IRUSR | S_IWUSR, errp);
1289e6bdef2SMarc-André Lureau         if (fd == -1) {
1299e6bdef2SMarc-André Lureau             return false;
1309e6bdef2SMarc-André Lureau         }
1319e6bdef2SMarc-André Lureau 
1329e6bdef2SMarc-André Lureau         if (fstat(fd, &b) < 0) {
1339e6bdef2SMarc-André Lureau             error_setg_errno(errp, errno, "Cannot stat file");
1349e6bdef2SMarc-André Lureau             goto fail_close;
1359e6bdef2SMarc-André Lureau         }
1369e6bdef2SMarc-André Lureau 
13735f7f3fbSMarc-André Lureau         if (fcntl(fd, F_SETLK, &lock)) {
1389e6bdef2SMarc-André Lureau             error_setg_errno(errp, errno, "Cannot lock pid file");
1399e6bdef2SMarc-André Lureau             goto fail_close;
1409e6bdef2SMarc-André Lureau         }
1419e6bdef2SMarc-André Lureau 
1429e6bdef2SMarc-André Lureau         /*
1439e6bdef2SMarc-André Lureau          * Now make sure the path we locked is the same one that now
1449e6bdef2SMarc-André Lureau          * exists on the filesystem.
1459e6bdef2SMarc-André Lureau          */
1469e6bdef2SMarc-André Lureau         if (stat(path, &a) < 0) {
1479e6bdef2SMarc-André Lureau             /*
1489e6bdef2SMarc-André Lureau              * PID file disappeared, someone else must be racing with
1499e6bdef2SMarc-André Lureau              * us, so try again.
1509e6bdef2SMarc-André Lureau              */
1519e6bdef2SMarc-André Lureau             close(fd);
1529e6bdef2SMarc-André Lureau             continue;
1539e6bdef2SMarc-André Lureau         }
1549e6bdef2SMarc-André Lureau 
1559e6bdef2SMarc-André Lureau         if (a.st_ino == b.st_ino) {
1569e6bdef2SMarc-André Lureau             break;
1579e6bdef2SMarc-André Lureau         }
1589e6bdef2SMarc-André Lureau 
1599e6bdef2SMarc-André Lureau         /*
1609e6bdef2SMarc-André Lureau          * PID file was recreated, someone else must be racing with
1619e6bdef2SMarc-André Lureau          * us, so try again.
1629e6bdef2SMarc-André Lureau          */
1639e6bdef2SMarc-André Lureau         close(fd);
1649e6bdef2SMarc-André Lureau     }
1659e6bdef2SMarc-André Lureau 
1669e6bdef2SMarc-André Lureau     if (ftruncate(fd, 0) < 0) {
1679e6bdef2SMarc-André Lureau         error_setg_errno(errp, errno, "Failed to truncate pid file");
1689e6bdef2SMarc-André Lureau         goto fail_unlink;
1699e6bdef2SMarc-André Lureau     }
1709e6bdef2SMarc-André Lureau 
1719e6bdef2SMarc-André Lureau     snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid());
17296eb9b2bSMarc-André Lureau     if (qemu_write_full(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
1739e6bdef2SMarc-André Lureau         error_setg(errp, "Failed to write pid file");
1749e6bdef2SMarc-André Lureau         goto fail_unlink;
1759e6bdef2SMarc-André Lureau     }
1769e6bdef2SMarc-André Lureau 
1779e6bdef2SMarc-André Lureau     return true;
1789e6bdef2SMarc-André Lureau 
1799e6bdef2SMarc-André Lureau fail_unlink:
1809e6bdef2SMarc-André Lureau     unlink(path);
1819e6bdef2SMarc-André Lureau fail_close:
1829e6bdef2SMarc-André Lureau     close(fd);
1839e6bdef2SMarc-André Lureau     return false;
1849e6bdef2SMarc-André Lureau }
1859e6bdef2SMarc-André Lureau 
186baacf047SPaolo Bonzini /* alloc shared memory pages */
qemu_anon_ram_alloc(size_t size,uint64_t * alignment,bool shared,bool noreserve)1878dbe22c6SDavid Hildenbrand void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared,
1888dbe22c6SDavid Hildenbrand                           bool noreserve)
189baacf047SPaolo Bonzini {
1908dbe22c6SDavid Hildenbrand     const uint32_t qemu_map_flags = (shared ? QEMU_MAP_SHARED : 0) |
1918dbe22c6SDavid Hildenbrand                                     (noreserve ? QEMU_MAP_NORESERVE : 0);
192baacf047SPaolo Bonzini     size_t align = QEMU_VMALLOC_ALIGN;
193b444f5c0SDavid Hildenbrand     void *ptr = qemu_ram_mmap(-1, size, align, qemu_map_flags, 0);
194baacf047SPaolo Bonzini 
1957dda5dc8SPaolo Bonzini     if (ptr == MAP_FAILED) {
19639228250SMarkus Armbruster         return NULL;
197baacf047SPaolo Bonzini     }
198baacf047SPaolo Bonzini 
199a2b257d6SIgor Mammedov     if (alignment) {
200a2b257d6SIgor Mammedov         *alignment = align;
201a2b257d6SIgor Mammedov     }
202c2dfc5baSMichael S. Tsirkin 
2036eebf958SPaolo Bonzini     trace_qemu_anon_ram_alloc(size, ptr);
204baacf047SPaolo Bonzini     return ptr;
205baacf047SPaolo Bonzini }
206baacf047SPaolo Bonzini 
qemu_anon_ram_free(void * ptr,size_t size)207e7a09b92SPaolo Bonzini void qemu_anon_ram_free(void *ptr, size_t size)
208e7a09b92SPaolo Bonzini {
209e7a09b92SPaolo Bonzini     trace_qemu_anon_ram_free(ptr, size);
21053adb9d4SMurilo Opsfelder Araujo     qemu_ram_munmap(-1, ptr, size);
211e7a09b92SPaolo Bonzini }
212e7a09b92SPaolo Bonzini 
qemu_socket_set_block(int fd)213ff5927baSMarc-André Lureau void qemu_socket_set_block(int fd)
214baacf047SPaolo Bonzini {
21522e135fcSMarc-André Lureau     g_unix_set_fd_nonblocking(fd, false, NULL);
216baacf047SPaolo Bonzini }
217baacf047SPaolo Bonzini 
qemu_socket_try_set_nonblock(int fd)218ff5927baSMarc-André Lureau int qemu_socket_try_set_nonblock(int fd)
219baacf047SPaolo Bonzini {
22022e135fcSMarc-André Lureau     return g_unix_set_fd_nonblocking(fd, true, NULL) ? 0 : -errno;
221894022e6SLaurent Vivier }
222894022e6SLaurent Vivier 
qemu_socket_set_nonblock(int fd)223ff5927baSMarc-André Lureau void qemu_socket_set_nonblock(int fd)
224894022e6SLaurent Vivier {
225894022e6SLaurent Vivier     int f;
226ff5927baSMarc-André Lureau     f = qemu_socket_try_set_nonblock(fd);
227894022e6SLaurent Vivier     assert(f == 0);
228baacf047SPaolo Bonzini }
229baacf047SPaolo Bonzini 
socket_set_fast_reuse(int fd)230606600a1SSebastian Ottlik int socket_set_fast_reuse(int fd)
231606600a1SSebastian Ottlik {
232606600a1SSebastian Ottlik     int val = 1, ret;
233606600a1SSebastian Ottlik 
234606600a1SSebastian Ottlik     ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
235606600a1SSebastian Ottlik                      (const char *)&val, sizeof(val));
236606600a1SSebastian Ottlik 
237606600a1SSebastian Ottlik     assert(ret == 0);
238606600a1SSebastian Ottlik 
239606600a1SSebastian Ottlik     return ret;
240606600a1SSebastian Ottlik }
241606600a1SSebastian Ottlik 
qemu_set_cloexec(int fd)242baacf047SPaolo Bonzini void qemu_set_cloexec(int fd)
243baacf047SPaolo Bonzini {
244baacf047SPaolo Bonzini     int f;
245baacf047SPaolo Bonzini     f = fcntl(fd, F_GETFD);
2467e6478e7SStefano Stabellini     assert(f != -1);
2477e6478e7SStefano Stabellini     f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
2487e6478e7SStefano Stabellini     assert(f != -1);
249baacf047SPaolo Bonzini }
250baacf047SPaolo Bonzini 
qemu_socketpair(int domain,int type,int protocol,int sv[2])2513c63b4e9SGuoyi Tu int qemu_socketpair(int domain, int type, int protocol, int sv[2])
2523c63b4e9SGuoyi Tu {
2533c63b4e9SGuoyi Tu     int ret;
2543c63b4e9SGuoyi Tu 
2553c63b4e9SGuoyi Tu #ifdef SOCK_CLOEXEC
2563c63b4e9SGuoyi Tu     ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
2573c63b4e9SGuoyi Tu     if (ret != -1 || errno != EINVAL) {
2583c63b4e9SGuoyi Tu         return ret;
2593c63b4e9SGuoyi Tu     }
2603c63b4e9SGuoyi Tu #endif
2613c63b4e9SGuoyi Tu     ret = socketpair(domain, type, protocol, sv);;
2623c63b4e9SGuoyi Tu     if (ret == 0) {
2633c63b4e9SGuoyi Tu         qemu_set_cloexec(sv[0]);
2643c63b4e9SGuoyi Tu         qemu_set_cloexec(sv[1]);
2653c63b4e9SGuoyi Tu     }
2663c63b4e9SGuoyi Tu 
2673c63b4e9SGuoyi Tu     return ret;
2683c63b4e9SGuoyi Tu }
2693c63b4e9SGuoyi Tu 
270e2ea3515SLaszlo Ersek char *
qemu_get_local_state_dir(void)2711fbf2665SMarc-André Lureau qemu_get_local_state_dir(void)
272e2ea3515SLaszlo Ersek {
2731fbf2665SMarc-André Lureau     return get_relocated_path(CONFIG_QEMU_LOCALSTATEDIR);
274e2ea3515SLaszlo Ersek }
27513401ba0SStefan Hajnoczi 
qemu_set_tty_echo(int fd,bool echo)27613401ba0SStefan Hajnoczi void qemu_set_tty_echo(int fd, bool echo)
27713401ba0SStefan Hajnoczi {
27813401ba0SStefan Hajnoczi     struct termios tty;
27913401ba0SStefan Hajnoczi 
28013401ba0SStefan Hajnoczi     tcgetattr(fd, &tty);
28113401ba0SStefan Hajnoczi 
28213401ba0SStefan Hajnoczi     if (echo) {
28313401ba0SStefan Hajnoczi         tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
28413401ba0SStefan Hajnoczi     } else {
28513401ba0SStefan Hajnoczi         tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
28613401ba0SStefan Hajnoczi     }
28713401ba0SStefan Hajnoczi 
28813401ba0SStefan Hajnoczi     tcsetattr(fd, TCSANOW, &tty);
28913401ba0SStefan Hajnoczi }
29010f5bff6SFam Zheng 
29129b838c0SDavid Hildenbrand #ifdef CONFIG_LINUX
sigbus_handler(int signal,siginfo_t * siginfo,void * ctx)29229b838c0SDavid Hildenbrand static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
29329b838c0SDavid Hildenbrand #else /* CONFIG_LINUX */
29438183310SPaolo Bonzini static void sigbus_handler(int signal)
29529b838c0SDavid Hildenbrand #endif /* CONFIG_LINUX */
29638183310SPaolo Bonzini {
2971e356fc1SJitendra Kolhe     int i;
298dba50678SDavid Hildenbrand 
299dba50678SDavid Hildenbrand     if (sigbus_memset_context) {
300dba50678SDavid Hildenbrand         for (i = 0; i < sigbus_memset_context->num_threads; i++) {
301dba50678SDavid Hildenbrand             MemsetThread *thread = &sigbus_memset_context->threads[i];
302dba50678SDavid Hildenbrand 
303dba50678SDavid Hildenbrand             if (qemu_thread_is_self(&thread->pgthread)) {
304dba50678SDavid Hildenbrand                 siglongjmp(thread->env, 1);
3051e356fc1SJitendra Kolhe             }
3061e356fc1SJitendra Kolhe         }
3071e356fc1SJitendra Kolhe     }
30829b838c0SDavid Hildenbrand 
30929b838c0SDavid Hildenbrand #ifdef CONFIG_LINUX
31029b838c0SDavid Hildenbrand     /*
31129b838c0SDavid Hildenbrand      * We assume that the MCE SIGBUS handler could have been registered. We
31229b838c0SDavid Hildenbrand      * should never receive BUS_MCEERR_AO on any of our threads, but only on
31329b838c0SDavid Hildenbrand      * the main thread registered for PR_MCE_KILL_EARLY. Further, we should not
31429b838c0SDavid Hildenbrand      * receive BUS_MCEERR_AR triggered by action of other threads on one of
31529b838c0SDavid Hildenbrand      * our threads. So, no need to check for unrelated SIGBUS when seeing one
31629b838c0SDavid Hildenbrand      * for our threads.
31729b838c0SDavid Hildenbrand      *
31829b838c0SDavid Hildenbrand      * We will forward to the MCE handler, which will either handle the SIGBUS
31929b838c0SDavid Hildenbrand      * or reinstall the default SIGBUS handler and reraise the SIGBUS. The
32029b838c0SDavid Hildenbrand      * default SIGBUS handler will crash the process, so we don't care.
32129b838c0SDavid Hildenbrand      */
32229b838c0SDavid Hildenbrand     if (sigbus_oldact.sa_flags & SA_SIGINFO) {
32329b838c0SDavid Hildenbrand         sigbus_oldact.sa_sigaction(signal, siginfo, ctx);
32429b838c0SDavid Hildenbrand         return;
32529b838c0SDavid Hildenbrand     }
32629b838c0SDavid Hildenbrand #endif /* CONFIG_LINUX */
3276556aadcSDavid Hildenbrand     warn_report("qemu_prealloc_mem: unrelated SIGBUS detected and ignored");
32838183310SPaolo Bonzini }
32938183310SPaolo Bonzini 
do_touch_pages(void * arg)3301e356fc1SJitendra Kolhe static void *do_touch_pages(void *arg)
3311e356fc1SJitendra Kolhe {
3321e356fc1SJitendra Kolhe     MemsetThread *memset_args = (MemsetThread *)arg;
3331e356fc1SJitendra Kolhe     sigset_t set, oldset;
3346c427ab9SDavid Hildenbrand     int ret = 0;
3351e356fc1SJitendra Kolhe 
336037fb5ebSbauerchen     /*
337037fb5ebSbauerchen      * On Linux, the page faults from the loop below can cause mmap_sem
338037fb5ebSbauerchen      * contention with allocation of the thread stacks.  Do not start
339037fb5ebSbauerchen      * clearing until all threads have been created.
340037fb5ebSbauerchen      */
341037fb5ebSbauerchen     qemu_mutex_lock(&page_mutex);
342dba50678SDavid Hildenbrand     while (!memset_args->context->all_threads_created) {
343037fb5ebSbauerchen         qemu_cond_wait(&page_cond, &page_mutex);
344037fb5ebSbauerchen     }
345037fb5ebSbauerchen     qemu_mutex_unlock(&page_mutex);
346037fb5ebSbauerchen 
3471e356fc1SJitendra Kolhe     /* unblock SIGBUS */
3481e356fc1SJitendra Kolhe     sigemptyset(&set);
3491e356fc1SJitendra Kolhe     sigaddset(&set, SIGBUS);
3501e356fc1SJitendra Kolhe     pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
3511e356fc1SJitendra Kolhe 
3521e356fc1SJitendra Kolhe     if (sigsetjmp(memset_args->env, 1)) {
3536c427ab9SDavid Hildenbrand         ret = -EFAULT;
3541e356fc1SJitendra Kolhe     } else {
355e947d47dSStefan Weil         char *addr = memset_args->addr;
356e947d47dSStefan Weil         size_t numpages = memset_args->numpages;
357e947d47dSStefan Weil         size_t hpagesize = memset_args->hpagesize;
358e947d47dSStefan Weil         size_t i;
3591e356fc1SJitendra Kolhe         for (i = 0; i < numpages; i++) {
3609dc44aa5SDaniel P. Berrange             /*
3619dc44aa5SDaniel P. Berrange              * Read & write back the same value, so we don't
3629dc44aa5SDaniel P. Berrange              * corrupt existing user/app data that might be
3639dc44aa5SDaniel P. Berrange              * stored.
3649dc44aa5SDaniel P. Berrange              *
3659dc44aa5SDaniel P. Berrange              * 'volatile' to stop compiler optimizing this away
3669dc44aa5SDaniel P. Berrange              * to a no-op
3679dc44aa5SDaniel P. Berrange              */
3689dc44aa5SDaniel P. Berrange             *(volatile char *)addr = *addr;
3691e356fc1SJitendra Kolhe             addr += hpagesize;
3701e356fc1SJitendra Kolhe         }
3711e356fc1SJitendra Kolhe     }
3721e356fc1SJitendra Kolhe     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
3736c427ab9SDavid Hildenbrand     return (void *)(uintptr_t)ret;
3741e356fc1SJitendra Kolhe }
3751e356fc1SJitendra Kolhe 
do_madv_populate_write_pages(void * arg)376a384bfa3SDavid Hildenbrand static void *do_madv_populate_write_pages(void *arg)
377a384bfa3SDavid Hildenbrand {
378a384bfa3SDavid Hildenbrand     MemsetThread *memset_args = (MemsetThread *)arg;
379a384bfa3SDavid Hildenbrand     const size_t size = memset_args->numpages * memset_args->hpagesize;
380a384bfa3SDavid Hildenbrand     char * const addr = memset_args->addr;
381a384bfa3SDavid Hildenbrand     int ret = 0;
382a384bfa3SDavid Hildenbrand 
383a384bfa3SDavid Hildenbrand     /* See do_touch_pages(). */
384a384bfa3SDavid Hildenbrand     qemu_mutex_lock(&page_mutex);
385dba50678SDavid Hildenbrand     while (!memset_args->context->all_threads_created) {
386a384bfa3SDavid Hildenbrand         qemu_cond_wait(&page_cond, &page_mutex);
387a384bfa3SDavid Hildenbrand     }
388a384bfa3SDavid Hildenbrand     qemu_mutex_unlock(&page_mutex);
389a384bfa3SDavid Hildenbrand 
390a384bfa3SDavid Hildenbrand     if (size && qemu_madvise(addr, size, QEMU_MADV_POPULATE_WRITE)) {
391a384bfa3SDavid Hildenbrand         ret = -errno;
392a384bfa3SDavid Hildenbrand     }
393a384bfa3SDavid Hildenbrand     return (void *)(uintptr_t)ret;
394a384bfa3SDavid Hildenbrand }
395a384bfa3SDavid Hildenbrand 
get_memset_num_threads(size_t hpagesize,size_t numpages,int max_threads)39689aec641SDavid Hildenbrand static inline int get_memset_num_threads(size_t hpagesize, size_t numpages,
3976556aadcSDavid Hildenbrand                                          int max_threads)
398dfd0dcc7SJitendra Kolhe {
399dfd0dcc7SJitendra Kolhe     long host_procs = sysconf(_SC_NPROCESSORS_ONLN);
400dfd0dcc7SJitendra Kolhe     int ret = 1;
401dfd0dcc7SJitendra Kolhe 
402dfd0dcc7SJitendra Kolhe     if (host_procs > 0) {
4036556aadcSDavid Hildenbrand         ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), max_threads);
404dfd0dcc7SJitendra Kolhe     }
40589aec641SDavid Hildenbrand 
40689aec641SDavid Hildenbrand     /* Especially with gigantic pages, don't create more threads than pages. */
40789aec641SDavid Hildenbrand     ret = MIN(ret, numpages);
40889aec641SDavid Hildenbrand     /* Don't start threads to prealloc comparatively little memory. */
40989aec641SDavid Hildenbrand     ret = MIN(ret, MAX(1, hpagesize * numpages / (64 * MiB)));
41089aec641SDavid Hildenbrand 
411dfd0dcc7SJitendra Kolhe     /* In case sysconf() fails, we fall back to single threaded */
412dfd0dcc7SJitendra Kolhe     return ret;
413dfd0dcc7SJitendra Kolhe }
414dfd0dcc7SJitendra Kolhe 
touch_all_pages(char * area,size_t hpagesize,size_t numpages,int max_threads,ThreadContext * tc,bool use_madv_populate_write)4156c427ab9SDavid Hildenbrand static int touch_all_pages(char *area, size_t hpagesize, size_t numpages,
416e04a34e5SDavid Hildenbrand                            int max_threads, ThreadContext *tc,
417e04a34e5SDavid Hildenbrand                            bool use_madv_populate_write)
4181e356fc1SJitendra Kolhe {
41978b3f67aSPaolo Bonzini     static gsize initialized = 0;
420dba50678SDavid Hildenbrand     MemsetContext context = {
4216556aadcSDavid Hildenbrand         .num_threads = get_memset_num_threads(hpagesize, numpages, max_threads),
422dba50678SDavid Hildenbrand     };
423037fb5ebSbauerchen     size_t numpages_per_thread, leftover;
424a384bfa3SDavid Hildenbrand     void *(*touch_fn)(void *);
4256c427ab9SDavid Hildenbrand     int ret = 0, i = 0;
4261e356fc1SJitendra Kolhe     char *addr = area;
4271e356fc1SJitendra Kolhe 
42878b3f67aSPaolo Bonzini     if (g_once_init_enter(&initialized)) {
42978b3f67aSPaolo Bonzini         qemu_mutex_init(&page_mutex);
43078b3f67aSPaolo Bonzini         qemu_cond_init(&page_cond);
43178b3f67aSPaolo Bonzini         g_once_init_leave(&initialized, 1);
43278b3f67aSPaolo Bonzini     }
43378b3f67aSPaolo Bonzini 
434a384bfa3SDavid Hildenbrand     if (use_madv_populate_write) {
435ac86e5c3SDavid Hildenbrand         /* Avoid creating a single thread for MADV_POPULATE_WRITE */
436ac86e5c3SDavid Hildenbrand         if (context.num_threads == 1) {
437ac86e5c3SDavid Hildenbrand             if (qemu_madvise(area, hpagesize * numpages,
438ac86e5c3SDavid Hildenbrand                              QEMU_MADV_POPULATE_WRITE)) {
439ac86e5c3SDavid Hildenbrand                 return -errno;
440ac86e5c3SDavid Hildenbrand             }
441ac86e5c3SDavid Hildenbrand             return 0;
442ac86e5c3SDavid Hildenbrand         }
443a384bfa3SDavid Hildenbrand         touch_fn = do_madv_populate_write_pages;
444a384bfa3SDavid Hildenbrand     } else {
445a384bfa3SDavid Hildenbrand         touch_fn = do_touch_pages;
446a384bfa3SDavid Hildenbrand     }
447a384bfa3SDavid Hildenbrand 
448dba50678SDavid Hildenbrand     context.threads = g_new0(MemsetThread, context.num_threads);
449dba50678SDavid Hildenbrand     numpages_per_thread = numpages / context.num_threads;
450dba50678SDavid Hildenbrand     leftover = numpages % context.num_threads;
451dba50678SDavid Hildenbrand     for (i = 0; i < context.num_threads; i++) {
452dba50678SDavid Hildenbrand         context.threads[i].addr = addr;
453dba50678SDavid Hildenbrand         context.threads[i].numpages = numpages_per_thread + (i < leftover);
454dba50678SDavid Hildenbrand         context.threads[i].hpagesize = hpagesize;
455dba50678SDavid Hildenbrand         context.threads[i].context = &context;
456e04a34e5SDavid Hildenbrand         if (tc) {
457e04a34e5SDavid Hildenbrand             thread_context_create_thread(tc, &context.threads[i].pgthread,
458e04a34e5SDavid Hildenbrand                                          "touch_pages",
459e04a34e5SDavid Hildenbrand                                          touch_fn, &context.threads[i],
460e04a34e5SDavid Hildenbrand                                          QEMU_THREAD_JOINABLE);
461e04a34e5SDavid Hildenbrand         } else {
462dba50678SDavid Hildenbrand             qemu_thread_create(&context.threads[i].pgthread, "touch_pages",
463dba50678SDavid Hildenbrand                                touch_fn, &context.threads[i],
4641e356fc1SJitendra Kolhe                                QEMU_THREAD_JOINABLE);
465e04a34e5SDavid Hildenbrand         }
466dba50678SDavid Hildenbrand         addr += context.threads[i].numpages * hpagesize;
467dba50678SDavid Hildenbrand     }
468dba50678SDavid Hildenbrand 
469dba50678SDavid Hildenbrand     if (!use_madv_populate_write) {
470dba50678SDavid Hildenbrand         sigbus_memset_context = &context;
4711e356fc1SJitendra Kolhe     }
472278fb162SBauerchen 
473278fb162SBauerchen     qemu_mutex_lock(&page_mutex);
474dba50678SDavid Hildenbrand     context.all_threads_created = true;
475037fb5ebSbauerchen     qemu_cond_broadcast(&page_cond);
476278fb162SBauerchen     qemu_mutex_unlock(&page_mutex);
477037fb5ebSbauerchen 
478dba50678SDavid Hildenbrand     for (i = 0; i < context.num_threads; i++) {
479dba50678SDavid Hildenbrand         int tmp = (uintptr_t)qemu_thread_join(&context.threads[i].pgthread);
4806c427ab9SDavid Hildenbrand 
4816c427ab9SDavid Hildenbrand         if (tmp) {
4826c427ab9SDavid Hildenbrand             ret = tmp;
4836c427ab9SDavid Hildenbrand         }
4841e356fc1SJitendra Kolhe     }
485dba50678SDavid Hildenbrand 
486dba50678SDavid Hildenbrand     if (!use_madv_populate_write) {
487dba50678SDavid Hildenbrand         sigbus_memset_context = NULL;
488dba50678SDavid Hildenbrand     }
489dba50678SDavid Hildenbrand     g_free(context.threads);
4901e356fc1SJitendra Kolhe 
4916c427ab9SDavid Hildenbrand     return ret;
4921e356fc1SJitendra Kolhe }
4931e356fc1SJitendra Kolhe 
madv_populate_write_possible(char * area,size_t pagesize)494a384bfa3SDavid Hildenbrand static bool madv_populate_write_possible(char *area, size_t pagesize)
495a384bfa3SDavid Hildenbrand {
496a384bfa3SDavid Hildenbrand     return !qemu_madvise(area, pagesize, QEMU_MADV_POPULATE_WRITE) ||
497a384bfa3SDavid Hildenbrand            errno != EINVAL;
498a384bfa3SDavid Hildenbrand }
499a384bfa3SDavid Hildenbrand 
qemu_prealloc_mem(int fd,char * area,size_t sz,int max_threads,ThreadContext * tc,Error ** errp)5006556aadcSDavid Hildenbrand void qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads,
501e04a34e5SDavid Hildenbrand                        ThreadContext *tc, Error **errp)
50238183310SPaolo Bonzini {
503a960d664SDavid Hildenbrand     static gsize initialized;
504b7bf8f56SStefan Weil     int ret;
5051e356fc1SJitendra Kolhe     size_t hpagesize = qemu_fd_getpagesize(fd);
5066556aadcSDavid Hildenbrand     size_t numpages = DIV_ROUND_UP(sz, hpagesize);
507a384bfa3SDavid Hildenbrand     bool use_madv_populate_write;
50829b838c0SDavid Hildenbrand     struct sigaction act;
50938183310SPaolo Bonzini 
510a384bfa3SDavid Hildenbrand     /*
511a384bfa3SDavid Hildenbrand      * Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
512a384bfa3SDavid Hildenbrand      * some special mappings, such as mapping /dev/mem.
513a384bfa3SDavid Hildenbrand      */
514a384bfa3SDavid Hildenbrand     use_madv_populate_write = madv_populate_write_possible(area, hpagesize);
515a384bfa3SDavid Hildenbrand 
516a384bfa3SDavid Hildenbrand     if (!use_madv_populate_write) {
517a960d664SDavid Hildenbrand         if (g_once_init_enter(&initialized)) {
518a960d664SDavid Hildenbrand             qemu_mutex_init(&sigbus_mutex);
519a960d664SDavid Hildenbrand             g_once_init_leave(&initialized, 1);
520a960d664SDavid Hildenbrand         }
521a960d664SDavid Hildenbrand 
522a960d664SDavid Hildenbrand         qemu_mutex_lock(&sigbus_mutex);
52338183310SPaolo Bonzini         memset(&act, 0, sizeof(act));
52429b838c0SDavid Hildenbrand #ifdef CONFIG_LINUX
52529b838c0SDavid Hildenbrand         act.sa_sigaction = &sigbus_handler;
52629b838c0SDavid Hildenbrand         act.sa_flags = SA_SIGINFO;
52729b838c0SDavid Hildenbrand #else /* CONFIG_LINUX */
52838183310SPaolo Bonzini         act.sa_handler = &sigbus_handler;
52938183310SPaolo Bonzini         act.sa_flags = 0;
53029b838c0SDavid Hildenbrand #endif /* CONFIG_LINUX */
53138183310SPaolo Bonzini 
53229b838c0SDavid Hildenbrand         ret = sigaction(SIGBUS, &act, &sigbus_oldact);
53338183310SPaolo Bonzini         if (ret) {
534dd4fc605SDavid Hildenbrand             qemu_mutex_unlock(&sigbus_mutex);
535056b68afSIgor Mammedov             error_setg_errno(errp, errno,
5366556aadcSDavid Hildenbrand                 "qemu_prealloc_mem: failed to install signal handler");
537056b68afSIgor Mammedov             return;
53838183310SPaolo Bonzini         }
539a384bfa3SDavid Hildenbrand     }
54038183310SPaolo Bonzini 
5411e356fc1SJitendra Kolhe     /* touch pages simultaneously */
542e04a34e5SDavid Hildenbrand     ret = touch_all_pages(area, hpagesize, numpages, max_threads, tc,
543a384bfa3SDavid Hildenbrand                           use_madv_populate_write);
5446c427ab9SDavid Hildenbrand     if (ret) {
5456c427ab9SDavid Hildenbrand         error_setg_errno(errp, -ret,
5466556aadcSDavid Hildenbrand                          "qemu_prealloc_mem: preallocating memory failed");
547056b68afSIgor Mammedov     }
54838183310SPaolo Bonzini 
549a384bfa3SDavid Hildenbrand     if (!use_madv_populate_write) {
55029b838c0SDavid Hildenbrand         ret = sigaction(SIGBUS, &sigbus_oldact, NULL);
55138183310SPaolo Bonzini         if (ret) {
552056b68afSIgor Mammedov             /* Terminate QEMU since it can't recover from error */
5536556aadcSDavid Hildenbrand             perror("qemu_prealloc_mem: failed to reinstall signal handler");
55438183310SPaolo Bonzini             exit(1);
55538183310SPaolo Bonzini         }
556a960d664SDavid Hildenbrand         qemu_mutex_unlock(&sigbus_mutex);
55738183310SPaolo Bonzini     }
558a384bfa3SDavid Hildenbrand }
559d57e4e48SDaniel P. Berrange 
qemu_get_pid_name(pid_t pid)5607dc9ae43SMichal Privoznik char *qemu_get_pid_name(pid_t pid)
5617dc9ae43SMichal Privoznik {
5627dc9ae43SMichal Privoznik     char *name = NULL;
5637dc9ae43SMichal Privoznik 
5647dc9ae43SMichal Privoznik #if defined(__FreeBSD__)
5657dc9ae43SMichal Privoznik     /* BSDs don't have /proc, but they provide a nice substitute */
5667dc9ae43SMichal Privoznik     struct kinfo_proc *proc = kinfo_getproc(pid);
5677dc9ae43SMichal Privoznik 
5687dc9ae43SMichal Privoznik     if (proc) {
5697dc9ae43SMichal Privoznik         name = g_strdup(proc->ki_comm);
5707dc9ae43SMichal Privoznik         free(proc);
5717dc9ae43SMichal Privoznik     }
5727dc9ae43SMichal Privoznik #else
5737dc9ae43SMichal Privoznik     /* Assume a system with reasonable procfs */
5747dc9ae43SMichal Privoznik     char *pid_path;
5757dc9ae43SMichal Privoznik     size_t len;
5767dc9ae43SMichal Privoznik 
5777dc9ae43SMichal Privoznik     pid_path = g_strdup_printf("/proc/%d/cmdline", pid);
5787dc9ae43SMichal Privoznik     g_file_get_contents(pid_path, &name, &len, NULL);
5797dc9ae43SMichal Privoznik     g_free(pid_path);
5807dc9ae43SMichal Privoznik #endif
5817dc9ae43SMichal Privoznik 
5827dc9ae43SMichal Privoznik     return name;
5837dc9ae43SMichal Privoznik }
5847dc9ae43SMichal Privoznik 
5857dc9ae43SMichal Privoznik 
qemu_alloc_stack(size_t * sz)5868737d9e0SPeter Lieven void *qemu_alloc_stack(size_t *sz)
5878737d9e0SPeter Lieven {
588*a1eaa628SAkihiko Odaki     void *ptr;
589fc3d1badSBrad Smith     int flags;
5907d992e4dSPeter Lieven #ifdef CONFIG_DEBUG_STACK_USAGE
5917d992e4dSPeter Lieven     void *ptr2;
5927d992e4dSPeter Lieven #endif
5938e3b0cbbSMarc-André Lureau     size_t pagesz = qemu_real_host_page_size();
5948737d9e0SPeter Lieven #ifdef _SC_THREAD_STACK_MIN
5958737d9e0SPeter Lieven     /* avoid stacks smaller than _SC_THREAD_STACK_MIN */
5968737d9e0SPeter Lieven     long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN);
5978737d9e0SPeter Lieven     *sz = MAX(MAX(min_stack_sz, 0), *sz);
5988737d9e0SPeter Lieven #endif
5998737d9e0SPeter Lieven     /* adjust stack size to a multiple of the page size */
6008737d9e0SPeter Lieven     *sz = ROUND_UP(*sz, pagesz);
6018737d9e0SPeter Lieven     /* allocate one extra page for the guard page */
6028737d9e0SPeter Lieven     *sz += pagesz;
6038737d9e0SPeter Lieven 
604fc3d1badSBrad Smith     flags = MAP_PRIVATE | MAP_ANONYMOUS;
605fc3d1badSBrad Smith #if defined(MAP_STACK) && defined(__OpenBSD__)
606fc3d1badSBrad Smith     /* Only enable MAP_STACK on OpenBSD. Other OS's such as
607fc3d1badSBrad Smith      * Linux/FreeBSD/NetBSD have a flag with the same name
608fc3d1badSBrad Smith      * but have differing functionality. OpenBSD will SEGV
609fc3d1badSBrad Smith      * if it spots execution with a stack pointer pointing
610fc3d1badSBrad Smith      * at memory that was not allocated with MAP_STACK.
611fc3d1badSBrad Smith      */
612fc3d1badSBrad Smith     flags |= MAP_STACK;
613fc3d1badSBrad Smith #endif
614fc3d1badSBrad Smith 
615fc3d1badSBrad Smith     ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE, flags, -1, 0);
6168737d9e0SPeter Lieven     if (ptr == MAP_FAILED) {
617e916a6e8SEduardo Habkost         perror("failed to allocate memory for stack");
6188737d9e0SPeter Lieven         abort();
6198737d9e0SPeter Lieven     }
6208737d9e0SPeter Lieven 
621*a1eaa628SAkihiko Odaki     /* Stack grows down -- guard page at the bottom. */
622*a1eaa628SAkihiko Odaki     if (mprotect(ptr, pagesz, PROT_NONE) != 0) {
623e916a6e8SEduardo Habkost         perror("failed to set up stack guard page");
6248737d9e0SPeter Lieven         abort();
6258737d9e0SPeter Lieven     }
6268737d9e0SPeter Lieven 
6277d992e4dSPeter Lieven #ifdef CONFIG_DEBUG_STACK_USAGE
6287d992e4dSPeter Lieven     for (ptr2 = ptr + pagesz; ptr2 < ptr + *sz; ptr2 += sizeof(uint32_t)) {
6297d992e4dSPeter Lieven         *(uint32_t *)ptr2 = 0xdeadbeaf;
6307d992e4dSPeter Lieven     }
6317d992e4dSPeter Lieven #endif
6327d992e4dSPeter Lieven 
6338737d9e0SPeter Lieven     return ptr;
6348737d9e0SPeter Lieven }
6358737d9e0SPeter Lieven 
6367d992e4dSPeter Lieven #ifdef CONFIG_DEBUG_STACK_USAGE
6377d992e4dSPeter Lieven static __thread unsigned int max_stack_usage;
6387d992e4dSPeter Lieven #endif
6397d992e4dSPeter Lieven 
qemu_free_stack(void * stack,size_t sz)6408737d9e0SPeter Lieven void qemu_free_stack(void *stack, size_t sz)
6418737d9e0SPeter Lieven {
6427d992e4dSPeter Lieven #ifdef CONFIG_DEBUG_STACK_USAGE
6437d992e4dSPeter Lieven     unsigned int usage;
6447d992e4dSPeter Lieven     void *ptr;
6457d992e4dSPeter Lieven 
6468e3b0cbbSMarc-André Lureau     for (ptr = stack + qemu_real_host_page_size(); ptr < stack + sz;
6477d992e4dSPeter Lieven          ptr += sizeof(uint32_t)) {
6487d992e4dSPeter Lieven         if (*(uint32_t *)ptr != 0xdeadbeaf) {
6497d992e4dSPeter Lieven             break;
6507d992e4dSPeter Lieven         }
6517d992e4dSPeter Lieven     }
6527d992e4dSPeter Lieven     usage = sz - (uintptr_t) (ptr - stack);
6537d992e4dSPeter Lieven     if (usage > max_stack_usage) {
6547d992e4dSPeter Lieven         error_report("thread %d max stack usage increased from %u to %u",
6557d992e4dSPeter Lieven                      qemu_get_thread_id(), max_stack_usage, usage);
6567d992e4dSPeter Lieven         max_stack_usage = usage;
6577d992e4dSPeter Lieven     }
6587d992e4dSPeter Lieven #endif
6597d992e4dSPeter Lieven 
6608737d9e0SPeter Lieven     munmap(stack, sz);
6618737d9e0SPeter Lieven }
662d98d4072SPaolo Bonzini 
663c905a368SDaniele Buono /*
664c905a368SDaniele Buono  * Disable CFI checks.
665d02d06f8SMichael Tokarev  * We are going to call a signal handler directly. Such handler may or may not
666c905a368SDaniele Buono  * have been defined in our binary, so there's no guarantee that the pointer
667c905a368SDaniele Buono  * used to set the handler is a cfi-valid pointer. Since the handlers are
668c905a368SDaniele Buono  * stored in kernel memory, changing the handler to an attacker-defined
669c905a368SDaniele Buono  * function requires being able to call a sigaction() syscall,
670c905a368SDaniele Buono  * which is not as easy as overwriting a pointer in memory.
671c905a368SDaniele Buono  */
672c905a368SDaniele Buono QEMU_DISABLE_CFI
sigaction_invoke(struct sigaction * action,struct qemu_signalfd_siginfo * info)673d98d4072SPaolo Bonzini void sigaction_invoke(struct sigaction *action,
674d98d4072SPaolo Bonzini                       struct qemu_signalfd_siginfo *info)
675d98d4072SPaolo Bonzini {
67602ffa034SPeter Maydell     siginfo_t si = {};
677d98d4072SPaolo Bonzini     si.si_signo = info->ssi_signo;
678d98d4072SPaolo Bonzini     si.si_errno = info->ssi_errno;
679d98d4072SPaolo Bonzini     si.si_code = info->ssi_code;
680d98d4072SPaolo Bonzini 
681d98d4072SPaolo Bonzini     /* Convert the minimal set of fields defined by POSIX.
682d98d4072SPaolo Bonzini      * Positive si_code values are reserved for kernel-generated
683d98d4072SPaolo Bonzini      * signals, where the valid siginfo fields are determined by
684d98d4072SPaolo Bonzini      * the signal number.  But according to POSIX, it is unspecified
685d98d4072SPaolo Bonzini      * whether SI_USER and SI_QUEUE have values less than or equal to
686d98d4072SPaolo Bonzini      * zero.
687d98d4072SPaolo Bonzini      */
688d98d4072SPaolo Bonzini     if (info->ssi_code == SI_USER || info->ssi_code == SI_QUEUE ||
689d98d4072SPaolo Bonzini         info->ssi_code <= 0) {
690d98d4072SPaolo Bonzini         /* SIGTERM, etc.  */
691d98d4072SPaolo Bonzini         si.si_pid = info->ssi_pid;
692d98d4072SPaolo Bonzini         si.si_uid = info->ssi_uid;
693d98d4072SPaolo Bonzini     } else if (info->ssi_signo == SIGILL || info->ssi_signo == SIGFPE ||
694d98d4072SPaolo Bonzini                info->ssi_signo == SIGSEGV || info->ssi_signo == SIGBUS) {
695d98d4072SPaolo Bonzini         si.si_addr = (void *)(uintptr_t)info->ssi_addr;
696d98d4072SPaolo Bonzini     } else if (info->ssi_signo == SIGCHLD) {
697d98d4072SPaolo Bonzini         si.si_pid = info->ssi_pid;
698d98d4072SPaolo Bonzini         si.si_status = info->ssi_status;
699d98d4072SPaolo Bonzini         si.si_uid = info->ssi_uid;
700d98d4072SPaolo Bonzini     }
701d98d4072SPaolo Bonzini     action->sa_sigaction(info->ssi_signo, &si, NULL);
702d98d4072SPaolo Bonzini }
703e47f4765SMichal Privoznik 
qemu_get_host_physmem(void)704ad06ef0eSAlex Bennée size_t qemu_get_host_physmem(void)
705ad06ef0eSAlex Bennée {
706ad06ef0eSAlex Bennée #ifdef _SC_PHYS_PAGES
707ad06ef0eSAlex Bennée     long pages = sysconf(_SC_PHYS_PAGES);
708ad06ef0eSAlex Bennée     if (pages > 0) {
7098e3b0cbbSMarc-André Lureau         if (pages > SIZE_MAX / qemu_real_host_page_size()) {
710ad06ef0eSAlex Bennée             return SIZE_MAX;
711ad06ef0eSAlex Bennée         } else {
7128e3b0cbbSMarc-André Lureau             return pages * qemu_real_host_page_size();
713ad06ef0eSAlex Bennée         }
714ad06ef0eSAlex Bennée     }
715ad06ef0eSAlex Bennée #endif
716ad06ef0eSAlex Bennée     return 0;
717ad06ef0eSAlex Bennée }
718e9c4e0a8SMarc-André Lureau 
qemu_msync(void * addr,size_t length,int fd)71973991a92SMarc-André Lureau int qemu_msync(void *addr, size_t length, int fd)
72073991a92SMarc-André Lureau {
72173991a92SMarc-André Lureau     size_t align_mask = ~(qemu_real_host_page_size() - 1);
72273991a92SMarc-André Lureau 
72373991a92SMarc-André Lureau     /**
72473991a92SMarc-André Lureau      * There are no strict reqs as per the length of mapping
72573991a92SMarc-André Lureau      * to be synced. Still the length needs to follow the address
72673991a92SMarc-André Lureau      * alignment changes. Additionally - round the size to the multiple
72773991a92SMarc-André Lureau      * of PAGE_SIZE
72873991a92SMarc-André Lureau      */
72973991a92SMarc-André Lureau     length += ((uintptr_t)addr & (qemu_real_host_page_size() - 1));
73073991a92SMarc-André Lureau     length = (length + ~align_mask) & align_mask;
73173991a92SMarc-André Lureau 
73273991a92SMarc-André Lureau     addr = (void *)((uintptr_t)addr & align_mask);
73373991a92SMarc-André Lureau 
73473991a92SMarc-André Lureau     return msync(addr, length, MS_SYNC);
73573991a92SMarc-André Lureau }
736