bsd-mem.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * memory management system call shims and definitions
  3. *
  4. * Copyright (c) 2013-15 Stacey D. Son
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /*
  20. * Copyright (c) 1982, 1986, 1993
  21. * The Regents of the University of California. All rights reserved.
  22. *
  23. * Redistribution and use in source and binary forms, with or without
  24. * modification, are permitted provided that the following conditions
  25. * are met:
  26. * 1. Redistributions of source code must retain the above copyright
  27. * notice, this list of conditions and the following disclaimer.
  28. * 2. Redistributions in binary form must reproduce the above copyright
  29. * notice, this list of conditions and the following disclaimer in the
  30. * documentation and/or other materials provided with the distribution.
  31. * 4. Neither the name of the University nor the names of its contributors
  32. * may be used to endorse or promote products derived from this software
  33. * without specific prior written permission.
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  36. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  39. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  40. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  41. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  42. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  43. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  44. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  45. * SUCH DAMAGE.
  46. */
  47. #ifndef BSD_USER_BSD_MEM_H
  48. #define BSD_USER_BSD_MEM_H
  49. #include <sys/types.h>
  50. #include <sys/ipc.h>
  51. #include <sys/mman.h>
  52. #include <sys/shm.h>
  53. #include <fcntl.h>
  54. #include "qemu-bsd.h"
  55. #include "exec/page-protection.h"
  56. extern struct bsd_shm_regions bsd_shm_regions[];
  57. extern abi_ulong target_brk;
  58. extern abi_ulong initial_target_brk;
  59. /* mmap(2) */
  60. static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
  61. abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
  62. abi_long arg8)
  63. {
  64. if (regpairs_aligned(cpu_env) != 0) {
  65. arg6 = arg7;
  66. arg7 = arg8;
  67. }
  68. return get_errno(target_mmap(arg1, arg2, arg3,
  69. target_to_host_bitmask(arg4, mmap_flags_tbl),
  70. arg5, target_arg64(arg6, arg7)));
  71. }
  72. /* munmap(2) */
  73. static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
  74. {
  75. return get_errno(target_munmap(arg1, arg2));
  76. }
  77. /* mprotect(2) */
  78. static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
  79. abi_long arg3)
  80. {
  81. return get_errno(target_mprotect(arg1, arg2, arg3));
  82. }
  83. /* msync(2) */
  84. static inline abi_long do_bsd_msync(abi_long addr, abi_long len, abi_long flags)
  85. {
  86. if (!guest_range_valid_untagged(addr, len)) {
  87. /* It seems odd, but POSIX wants this to be ENOMEM */
  88. return -TARGET_ENOMEM;
  89. }
  90. return get_errno(msync(g2h_untagged(addr), len, flags));
  91. }
  92. /* mlock(2) */
  93. static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
  94. {
  95. if (!guest_range_valid_untagged(arg1, arg2)) {
  96. return -TARGET_EINVAL;
  97. }
  98. return get_errno(mlock(g2h_untagged(arg1), arg2));
  99. }
  100. /* munlock(2) */
  101. static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
  102. {
  103. if (!guest_range_valid_untagged(arg1, arg2)) {
  104. return -TARGET_EINVAL;
  105. }
  106. return get_errno(munlock(g2h_untagged(arg1), arg2));
  107. }
  108. /* mlockall(2) */
  109. static inline abi_long do_bsd_mlockall(abi_long arg1)
  110. {
  111. return get_errno(mlockall(arg1));
  112. }
  113. /* munlockall(2) */
  114. static inline abi_long do_bsd_munlockall(void)
  115. {
  116. return get_errno(munlockall());
  117. }
  118. /* madvise(2) */
  119. static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
  120. abi_long arg3)
  121. {
  122. abi_ulong len;
  123. int ret = 0;
  124. abi_long start = arg1;
  125. abi_long len_in = arg2;
  126. abi_long advice = arg3;
  127. if (start & ~TARGET_PAGE_MASK) {
  128. return -TARGET_EINVAL;
  129. }
  130. if (len_in == 0) {
  131. return 0;
  132. }
  133. len = TARGET_PAGE_ALIGN(len_in);
  134. if (len == 0 || !guest_range_valid_untagged(start, len)) {
  135. return -TARGET_EINVAL;
  136. }
  137. /*
  138. * Most advice values are hints, so ignoring and returning success is ok.
  139. *
  140. * However, some advice values such as MADV_DONTNEED, are not hints and
  141. * need to be emulated.
  142. *
  143. * A straight passthrough for those may not be safe because qemu sometimes
  144. * turns private file-backed mappings into anonymous mappings.
  145. * If all guest pages have PAGE_PASSTHROUGH set, mappings have the
  146. * same semantics for the host as for the guest.
  147. *
  148. * MADV_DONTNEED is passed through, if possible.
  149. * If passthrough isn't possible, we nevertheless (wrongly!) return
  150. * success, which is broken but some userspace programs fail to work
  151. * otherwise. Completely implementing such emulation is quite complicated
  152. * though.
  153. */
  154. mmap_lock();
  155. switch (advice) {
  156. case MADV_DONTNEED:
  157. if (page_check_range(start, len, PAGE_PASSTHROUGH)) {
  158. ret = get_errno(madvise(g2h_untagged(start), len, advice));
  159. if (ret == 0) {
  160. page_reset_target_data(start, start + len - 1);
  161. }
  162. }
  163. }
  164. mmap_unlock();
  165. return ret;
  166. }
  167. /* minherit(2) */
  168. static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
  169. abi_long inherit)
  170. {
  171. return get_errno(minherit(g2h_untagged(addr), len, inherit));
  172. }
  173. /* mincore(2) */
  174. static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
  175. abi_ulong target_vec)
  176. {
  177. abi_long ret;
  178. void *p;
  179. abi_ulong vec_len = DIV_ROUND_UP(len, TARGET_PAGE_SIZE);
  180. if (!guest_range_valid_untagged(target_addr, len)
  181. || !page_check_range(target_addr, len, PAGE_VALID)) {
  182. return -TARGET_EFAULT;
  183. }
  184. p = lock_user(VERIFY_WRITE, target_vec, vec_len, 0);
  185. if (p == NULL) {
  186. return -TARGET_EFAULT;
  187. }
  188. ret = get_errno(mincore(g2h_untagged(target_addr), len, p));
  189. unlock_user(p, target_vec, vec_len);
  190. return ret;
  191. }
  192. /* do_brk() must return target values and target errnos. */
  193. static inline abi_long do_obreak(abi_ulong brk_val)
  194. {
  195. abi_long mapped_addr;
  196. abi_ulong new_brk;
  197. abi_ulong old_brk;
  198. /* brk pointers are always untagged */
  199. /* do not allow to shrink below initial brk value */
  200. if (brk_val < initial_target_brk) {
  201. return target_brk;
  202. }
  203. new_brk = TARGET_PAGE_ALIGN(brk_val);
  204. old_brk = TARGET_PAGE_ALIGN(target_brk);
  205. /* new and old target_brk might be on the same page */
  206. if (new_brk == old_brk) {
  207. target_brk = brk_val;
  208. return target_brk;
  209. }
  210. /* Release heap if necessary */
  211. if (new_brk < old_brk) {
  212. target_munmap(new_brk, old_brk - new_brk);
  213. target_brk = brk_val;
  214. return target_brk;
  215. }
  216. mapped_addr = target_mmap(old_brk, new_brk - old_brk,
  217. PROT_READ | PROT_WRITE,
  218. MAP_FIXED | MAP_EXCL | MAP_ANON | MAP_PRIVATE,
  219. -1, 0);
  220. if (mapped_addr == old_brk) {
  221. target_brk = brk_val;
  222. return target_brk;
  223. }
  224. /* For everything else, return the previous break. */
  225. return target_brk;
  226. }
  227. /* shm_open(2) */
  228. static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
  229. abi_long arg3)
  230. {
  231. int ret;
  232. void *p;
  233. if (arg1 == (uintptr_t)SHM_ANON) {
  234. p = SHM_ANON;
  235. } else {
  236. p = lock_user_string(arg1);
  237. if (p == NULL) {
  238. return -TARGET_EFAULT;
  239. }
  240. }
  241. ret = get_errno(shm_open(p, target_to_host_bitmask(arg2, fcntl_flags_tbl),
  242. arg3));
  243. if (p != SHM_ANON) {
  244. unlock_user(p, arg1, 0);
  245. }
  246. return ret;
  247. }
  248. /* shm_unlink(2) */
  249. static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
  250. {
  251. int ret;
  252. void *p;
  253. p = lock_user_string(arg1);
  254. if (p == NULL) {
  255. return -TARGET_EFAULT;
  256. }
  257. ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
  258. unlock_user(p, arg1, 0);
  259. return ret;
  260. }
  261. /* shmget(2) */
  262. static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
  263. abi_long arg3)
  264. {
  265. return get_errno(shmget(arg1, arg2, arg3));
  266. }
  267. /* shmctl(2) */
  268. static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
  269. abi_ulong buff)
  270. {
  271. struct shmid_ds dsarg;
  272. abi_long ret = -TARGET_EINVAL;
  273. cmd &= 0xff;
  274. switch (cmd) {
  275. case IPC_STAT:
  276. if (target_to_host_shmid_ds(&dsarg, buff)) {
  277. return -TARGET_EFAULT;
  278. }
  279. ret = get_errno(shmctl(shmid, cmd, &dsarg));
  280. if (host_to_target_shmid_ds(buff, &dsarg)) {
  281. return -TARGET_EFAULT;
  282. }
  283. break;
  284. case IPC_SET:
  285. if (target_to_host_shmid_ds(&dsarg, buff)) {
  286. return -TARGET_EFAULT;
  287. }
  288. ret = get_errno(shmctl(shmid, cmd, &dsarg));
  289. break;
  290. case IPC_RMID:
  291. ret = get_errno(shmctl(shmid, cmd, NULL));
  292. break;
  293. default:
  294. ret = -TARGET_EINVAL;
  295. break;
  296. }
  297. return ret;
  298. }
  299. /* shmat(2) */
  300. static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
  301. {
  302. abi_ulong raddr;
  303. abi_long ret;
  304. struct shmid_ds shm_info;
  305. /* Find out the length of the shared memory segment. */
  306. ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
  307. if (is_error(ret)) {
  308. /* Can't get the length */
  309. return ret;
  310. }
  311. if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
  312. return -TARGET_EINVAL;
  313. }
  314. WITH_MMAP_LOCK_GUARD() {
  315. void *host_raddr;
  316. if (shmaddr) {
  317. host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
  318. } else {
  319. abi_ulong mmap_start;
  320. mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
  321. if (mmap_start == -1) {
  322. return -TARGET_ENOMEM;
  323. }
  324. host_raddr = shmat(shmid, g2h_untagged(mmap_start),
  325. shmflg | SHM_REMAP);
  326. }
  327. if (host_raddr == (void *)-1) {
  328. return get_errno(-1);
  329. }
  330. raddr = h2g(host_raddr);
  331. page_set_flags(raddr, raddr + shm_info.shm_segsz - 1,
  332. PAGE_VALID | PAGE_RESET | PAGE_READ |
  333. (shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
  334. for (int i = 0; i < N_BSD_SHM_REGIONS; i++) {
  335. if (bsd_shm_regions[i].start == 0) {
  336. bsd_shm_regions[i].start = raddr;
  337. bsd_shm_regions[i].size = shm_info.shm_segsz;
  338. break;
  339. }
  340. }
  341. }
  342. return raddr;
  343. }
  344. /* shmdt(2) */
  345. static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
  346. {
  347. abi_long ret;
  348. WITH_MMAP_LOCK_GUARD() {
  349. int i;
  350. for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
  351. if (bsd_shm_regions[i].start == shmaddr) {
  352. break;
  353. }
  354. }
  355. if (i == N_BSD_SHM_REGIONS) {
  356. return -TARGET_EINVAL;
  357. }
  358. ret = get_errno(shmdt(g2h_untagged(shmaddr)));
  359. if (ret == 0) {
  360. abi_ulong size = bsd_shm_regions[i].size;
  361. bsd_shm_regions[i].start = 0;
  362. page_set_flags(shmaddr, shmaddr + size - 1, 0);
  363. mmap_reserve(shmaddr, size);
  364. }
  365. }
  366. return ret;
  367. }
  368. static inline abi_long do_bsd_vadvise(void)
  369. {
  370. /* See sys_ovadvise() in vm_unix.c */
  371. return -TARGET_EINVAL;
  372. }
  373. static inline abi_long do_bsd_sbrk(void)
  374. {
  375. /* see sys_sbrk() in vm_mmap.c */
  376. return -TARGET_EOPNOTSUPP;
  377. }
  378. static inline abi_long do_bsd_sstk(void)
  379. {
  380. /* see sys_sstk() in vm_mmap.c */
  381. return -TARGET_EOPNOTSUPP;
  382. }
  383. #endif /* BSD_USER_BSD_MEM_H */