2
0

bsd-mem.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. #include "user/page-protection.h"
  57. extern struct bsd_shm_regions bsd_shm_regions[];
  58. extern abi_ulong target_brk;
  59. extern abi_ulong initial_target_brk;
  60. /* mmap(2) */
  61. static inline abi_long do_bsd_mmap(void *cpu_env, abi_long arg1, abi_long arg2,
  62. abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7,
  63. abi_long arg8)
  64. {
  65. if (regpairs_aligned(cpu_env) != 0) {
  66. arg6 = arg7;
  67. arg7 = arg8;
  68. }
  69. return get_errno(target_mmap(arg1, arg2, arg3,
  70. target_to_host_bitmask(arg4, mmap_flags_tbl),
  71. arg5, target_arg64(arg6, arg7)));
  72. }
  73. /* munmap(2) */
  74. static inline abi_long do_bsd_munmap(abi_long arg1, abi_long arg2)
  75. {
  76. return get_errno(target_munmap(arg1, arg2));
  77. }
  78. /* mprotect(2) */
  79. static inline abi_long do_bsd_mprotect(abi_long arg1, abi_long arg2,
  80. abi_long arg3)
  81. {
  82. return get_errno(target_mprotect(arg1, arg2, arg3));
  83. }
  84. /* msync(2) */
  85. static inline abi_long do_bsd_msync(abi_long addr, abi_long len, abi_long flags)
  86. {
  87. if (!guest_range_valid_untagged(addr, len)) {
  88. /* It seems odd, but POSIX wants this to be ENOMEM */
  89. return -TARGET_ENOMEM;
  90. }
  91. return get_errno(msync(g2h_untagged(addr), len, flags));
  92. }
  93. /* mlock(2) */
  94. static inline abi_long do_bsd_mlock(abi_long arg1, abi_long arg2)
  95. {
  96. if (!guest_range_valid_untagged(arg1, arg2)) {
  97. return -TARGET_EINVAL;
  98. }
  99. return get_errno(mlock(g2h_untagged(arg1), arg2));
  100. }
  101. /* munlock(2) */
  102. static inline abi_long do_bsd_munlock(abi_long arg1, abi_long arg2)
  103. {
  104. if (!guest_range_valid_untagged(arg1, arg2)) {
  105. return -TARGET_EINVAL;
  106. }
  107. return get_errno(munlock(g2h_untagged(arg1), arg2));
  108. }
  109. /* mlockall(2) */
  110. static inline abi_long do_bsd_mlockall(abi_long arg1)
  111. {
  112. return get_errno(mlockall(arg1));
  113. }
  114. /* munlockall(2) */
  115. static inline abi_long do_bsd_munlockall(void)
  116. {
  117. return get_errno(munlockall());
  118. }
  119. /* madvise(2) */
  120. static inline abi_long do_bsd_madvise(abi_long arg1, abi_long arg2,
  121. abi_long arg3)
  122. {
  123. abi_ulong len;
  124. int ret = 0;
  125. abi_long start = arg1;
  126. abi_long len_in = arg2;
  127. abi_long advice = arg3;
  128. if (start & ~TARGET_PAGE_MASK) {
  129. return -TARGET_EINVAL;
  130. }
  131. if (len_in == 0) {
  132. return 0;
  133. }
  134. len = TARGET_PAGE_ALIGN(len_in);
  135. if (len == 0 || !guest_range_valid_untagged(start, len)) {
  136. return -TARGET_EINVAL;
  137. }
  138. /*
  139. * Most advice values are hints, so ignoring and returning success is ok.
  140. *
  141. * However, some advice values such as MADV_DONTNEED, are not hints and
  142. * need to be emulated.
  143. *
  144. * A straight passthrough for those may not be safe because qemu sometimes
  145. * turns private file-backed mappings into anonymous mappings.
  146. * If all guest pages have PAGE_PASSTHROUGH set, mappings have the
  147. * same semantics for the host as for the guest.
  148. *
  149. * MADV_DONTNEED is passed through, if possible.
  150. * If passthrough isn't possible, we nevertheless (wrongly!) return
  151. * success, which is broken but some userspace programs fail to work
  152. * otherwise. Completely implementing such emulation is quite complicated
  153. * though.
  154. */
  155. mmap_lock();
  156. switch (advice) {
  157. case MADV_DONTNEED:
  158. if (page_check_range(start, len, PAGE_PASSTHROUGH)) {
  159. ret = get_errno(madvise(g2h_untagged(start), len, advice));
  160. if (ret == 0) {
  161. page_reset_target_data(start, start + len - 1);
  162. }
  163. }
  164. }
  165. mmap_unlock();
  166. return ret;
  167. }
  168. /* minherit(2) */
  169. static inline abi_long do_bsd_minherit(abi_long addr, abi_long len,
  170. abi_long inherit)
  171. {
  172. return get_errno(minherit(g2h_untagged(addr), len, inherit));
  173. }
  174. /* mincore(2) */
  175. static inline abi_long do_bsd_mincore(abi_ulong target_addr, abi_ulong len,
  176. abi_ulong target_vec)
  177. {
  178. abi_long ret;
  179. void *p;
  180. abi_ulong vec_len = DIV_ROUND_UP(len, TARGET_PAGE_SIZE);
  181. if (!guest_range_valid_untagged(target_addr, len)
  182. || !page_check_range(target_addr, len, PAGE_VALID)) {
  183. return -TARGET_EFAULT;
  184. }
  185. p = lock_user(VERIFY_WRITE, target_vec, vec_len, 0);
  186. if (p == NULL) {
  187. return -TARGET_EFAULT;
  188. }
  189. ret = get_errno(mincore(g2h_untagged(target_addr), len, p));
  190. unlock_user(p, target_vec, vec_len);
  191. return ret;
  192. }
  193. /* do_brk() must return target values and target errnos. */
  194. static inline abi_long do_obreak(abi_ulong brk_val)
  195. {
  196. abi_long mapped_addr;
  197. abi_ulong new_brk;
  198. abi_ulong old_brk;
  199. /* brk pointers are always untagged */
  200. /* do not allow to shrink below initial brk value */
  201. if (brk_val < initial_target_brk) {
  202. return target_brk;
  203. }
  204. new_brk = TARGET_PAGE_ALIGN(brk_val);
  205. old_brk = TARGET_PAGE_ALIGN(target_brk);
  206. /* new and old target_brk might be on the same page */
  207. if (new_brk == old_brk) {
  208. target_brk = brk_val;
  209. return target_brk;
  210. }
  211. /* Release heap if necessary */
  212. if (new_brk < old_brk) {
  213. target_munmap(new_brk, old_brk - new_brk);
  214. target_brk = brk_val;
  215. return target_brk;
  216. }
  217. mapped_addr = target_mmap(old_brk, new_brk - old_brk,
  218. PROT_READ | PROT_WRITE,
  219. MAP_FIXED | MAP_EXCL | MAP_ANON | MAP_PRIVATE,
  220. -1, 0);
  221. if (mapped_addr == old_brk) {
  222. target_brk = brk_val;
  223. return target_brk;
  224. }
  225. /* For everything else, return the previous break. */
  226. return target_brk;
  227. }
  228. /* shm_open(2) */
  229. static inline abi_long do_bsd_shm_open(abi_ulong arg1, abi_long arg2,
  230. abi_long arg3)
  231. {
  232. int ret;
  233. void *p;
  234. if (arg1 == (uintptr_t)SHM_ANON) {
  235. p = SHM_ANON;
  236. } else {
  237. p = lock_user_string(arg1);
  238. if (p == NULL) {
  239. return -TARGET_EFAULT;
  240. }
  241. }
  242. ret = get_errno(shm_open(p, target_to_host_bitmask(arg2, fcntl_flags_tbl),
  243. arg3));
  244. if (p != SHM_ANON) {
  245. unlock_user(p, arg1, 0);
  246. }
  247. return ret;
  248. }
  249. /* shm_unlink(2) */
  250. static inline abi_long do_bsd_shm_unlink(abi_ulong arg1)
  251. {
  252. int ret;
  253. void *p;
  254. p = lock_user_string(arg1);
  255. if (p == NULL) {
  256. return -TARGET_EFAULT;
  257. }
  258. ret = get_errno(shm_unlink(p)); /* XXX path(p)? */
  259. unlock_user(p, arg1, 0);
  260. return ret;
  261. }
  262. /* shmget(2) */
  263. static inline abi_long do_bsd_shmget(abi_long arg1, abi_ulong arg2,
  264. abi_long arg3)
  265. {
  266. return get_errno(shmget(arg1, arg2, arg3));
  267. }
  268. /* shmctl(2) */
  269. static inline abi_long do_bsd_shmctl(abi_long shmid, abi_long cmd,
  270. abi_ulong buff)
  271. {
  272. struct shmid_ds dsarg;
  273. abi_long ret = -TARGET_EINVAL;
  274. cmd &= 0xff;
  275. switch (cmd) {
  276. case IPC_STAT:
  277. if (target_to_host_shmid_ds(&dsarg, buff)) {
  278. return -TARGET_EFAULT;
  279. }
  280. ret = get_errno(shmctl(shmid, cmd, &dsarg));
  281. if (host_to_target_shmid_ds(buff, &dsarg)) {
  282. return -TARGET_EFAULT;
  283. }
  284. break;
  285. case IPC_SET:
  286. if (target_to_host_shmid_ds(&dsarg, buff)) {
  287. return -TARGET_EFAULT;
  288. }
  289. ret = get_errno(shmctl(shmid, cmd, &dsarg));
  290. break;
  291. case IPC_RMID:
  292. ret = get_errno(shmctl(shmid, cmd, NULL));
  293. break;
  294. default:
  295. ret = -TARGET_EINVAL;
  296. break;
  297. }
  298. return ret;
  299. }
  300. /* shmat(2) */
  301. static inline abi_long do_bsd_shmat(int shmid, abi_ulong shmaddr, int shmflg)
  302. {
  303. abi_ulong raddr;
  304. abi_long ret;
  305. struct shmid_ds shm_info;
  306. /* Find out the length of the shared memory segment. */
  307. ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
  308. if (is_error(ret)) {
  309. /* Can't get the length */
  310. return ret;
  311. }
  312. if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
  313. return -TARGET_EINVAL;
  314. }
  315. WITH_MMAP_LOCK_GUARD() {
  316. void *host_raddr;
  317. if (shmaddr) {
  318. host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
  319. } else {
  320. abi_ulong alignment;
  321. abi_ulong mmap_start;
  322. alignment = 0; /* alignment above page size not required */
  323. mmap_start = mmap_find_vma(0, shm_info.shm_segsz, alignment);
  324. if (mmap_start == -1) {
  325. return -TARGET_ENOMEM;
  326. }
  327. host_raddr = shmat(shmid, g2h_untagged(mmap_start),
  328. shmflg | SHM_REMAP);
  329. }
  330. if (host_raddr == (void *)-1) {
  331. return get_errno(-1);
  332. }
  333. raddr = h2g(host_raddr);
  334. page_set_flags(raddr, raddr + shm_info.shm_segsz - 1,
  335. PAGE_VALID | PAGE_RESET | PAGE_READ |
  336. (shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
  337. for (int i = 0; i < N_BSD_SHM_REGIONS; i++) {
  338. if (bsd_shm_regions[i].start == 0) {
  339. bsd_shm_regions[i].start = raddr;
  340. bsd_shm_regions[i].size = shm_info.shm_segsz;
  341. break;
  342. }
  343. }
  344. }
  345. return raddr;
  346. }
  347. /* shmdt(2) */
  348. static inline abi_long do_bsd_shmdt(abi_ulong shmaddr)
  349. {
  350. abi_long ret;
  351. WITH_MMAP_LOCK_GUARD() {
  352. int i;
  353. for (i = 0; i < N_BSD_SHM_REGIONS; ++i) {
  354. if (bsd_shm_regions[i].start == shmaddr) {
  355. break;
  356. }
  357. }
  358. if (i == N_BSD_SHM_REGIONS) {
  359. return -TARGET_EINVAL;
  360. }
  361. ret = get_errno(shmdt(g2h_untagged(shmaddr)));
  362. if (ret == 0) {
  363. abi_ulong size = bsd_shm_regions[i].size;
  364. bsd_shm_regions[i].start = 0;
  365. page_set_flags(shmaddr, shmaddr + size - 1, 0);
  366. mmap_reserve(shmaddr, size);
  367. }
  368. }
  369. return ret;
  370. }
  371. static inline abi_long do_bsd_vadvise(void)
  372. {
  373. /* See sys_ovadvise() in vm_unix.c */
  374. return -TARGET_EINVAL;
  375. }
  376. static inline abi_long do_bsd_sbrk(void)
  377. {
  378. /* see sys_sbrk() in vm_mmap.c */
  379. return -TARGET_EOPNOTSUPP;
  380. }
  381. static inline abi_long do_bsd_sstk(void)
  382. {
  383. /* see sys_sstk() in vm_mmap.c */
  384. return -TARGET_EOPNOTSUPP;
  385. }
  386. #endif /* BSD_USER_BSD_MEM_H */