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