lwp_user_mm.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-10-28 Jesven first version
  9. * 2021-02-06 lizhirui fixed fixed vtable size problem
  10. * 2021-02-12 lizhirui add 64-bit support for lwp_brk
  11. * 2021-02-19 lizhirui add riscv64 support for lwp_user_accessable and lwp_get_from_user
  12. * 2021-06-07 lizhirui modify user space bound check
  13. * 2022-12-25 wangxiaoyao adapt to new mm
  14. * 2023-08-12 Shell Fix parameter passing of lwp_mmap()/lwp_munmap()
  15. * 2023-08-29 Shell Add API accessible()/data_get()/data_set()/data_put()
  16. * 2023-09-13 Shell Add lwp_memcpy and support run-time choice of memcpy base on memory attr
  17. * 2023-09-19 Shell add lwp_user_memory_remap_to_kernel
  18. */
  19. #include <rtthread.h>
  20. #include <rthw.h>
  21. #include <string.h>
  22. #ifdef ARCH_MM_MMU
  23. #include <lwp.h>
  24. #include <lwp_arch.h>
  25. #include <lwp_mm.h>
  26. #include <lwp_user_mm.h>
  27. #include <mm_aspace.h>
  28. #include <mm_fault.h>
  29. #include <mm_flag.h>
  30. #include <mm_page.h>
  31. #include <mmu.h>
  32. #include <page.h>
  33. #ifdef RT_USING_MUSLLIBC
  34. #include "libc_musl.h"
  35. #endif
  36. #define DBG_TAG "LwP.mman"
  37. #define DBG_LVL DBG_INFO
  38. #include <rtdbg.h>
  39. #include <stdlib.h>
  40. #define STACK_OBJ _null_object
  41. static void _init_lwp_objs(struct rt_lwp_objs *lwp_objs, rt_aspace_t aspace);
  42. static const char *_null_get_name(rt_varea_t varea)
  43. {
  44. return "null";
  45. }
  46. static void _null_page_fault(struct rt_varea *varea,
  47. struct rt_aspace_fault_msg *msg)
  48. {
  49. static void *null_page;
  50. if (!null_page)
  51. {
  52. null_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  53. if (null_page)
  54. memset(null_page, 0, ARCH_PAGE_SIZE);
  55. else
  56. return;
  57. }
  58. msg->response.status = MM_FAULT_STATUS_OK;
  59. msg->response.size = ARCH_PAGE_SIZE;
  60. msg->response.vaddr = null_page;
  61. }
  62. static rt_err_t _null_shrink(rt_varea_t varea, void *new_start, rt_size_t size)
  63. {
  64. return RT_EOK;
  65. }
  66. static rt_err_t _null_split(struct rt_varea *existed, void *unmap_start, rt_size_t unmap_len, struct rt_varea *subset)
  67. {
  68. return RT_EOK;
  69. }
  70. static rt_err_t _null_expand(struct rt_varea *varea, void *new_vaddr, rt_size_t size)
  71. {
  72. return RT_EOK;
  73. }
  74. static void _null_page_read(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
  75. {
  76. void *dest = msg->buffer_vaddr;
  77. memset(dest, 0, ARCH_PAGE_SIZE);
  78. msg->response.status = MM_FAULT_STATUS_OK;
  79. return ;
  80. }
  81. static void _null_page_write(struct rt_varea *varea, struct rt_aspace_io_msg *msg)
  82. {
  83. /* write operation is not allowed */
  84. msg->response.status = MM_FAULT_STATUS_UNRECOVERABLE;
  85. return ;
  86. }
  87. static struct rt_mem_obj _null_object = {
  88. .get_name = _null_get_name,
  89. .hint_free = RT_NULL,
  90. .on_page_fault = _null_page_fault,
  91. .page_read = _null_page_read,
  92. .page_write = _null_page_write,
  93. .on_varea_expand = _null_expand,
  94. .on_varea_shrink = _null_shrink,
  95. .on_varea_split = _null_split,
  96. };
  97. int lwp_user_space_init(struct rt_lwp *lwp, rt_bool_t is_fork)
  98. {
  99. void *stk_addr;
  100. int err = -RT_ENOMEM;
  101. const size_t flags = MMF_MAP_PRIVATE;
  102. lwp->lwp_obj = rt_malloc(sizeof(struct rt_lwp_objs));
  103. if (lwp->lwp_obj)
  104. {
  105. err = arch_user_space_init(lwp);
  106. if (err == RT_EOK)
  107. {
  108. _init_lwp_objs(lwp->lwp_obj, lwp->aspace);
  109. if (!is_fork)
  110. {
  111. stk_addr = (void *)USER_STACK_VSTART;
  112. err = rt_aspace_map(lwp->aspace, &stk_addr,
  113. USER_STACK_VEND - USER_STACK_VSTART,
  114. MMU_MAP_U_RWCB, flags, &STACK_OBJ, 0);
  115. }
  116. }
  117. }
  118. return err;
  119. }
  120. void lwp_aspace_switch(struct rt_thread *thread)
  121. {
  122. struct rt_lwp *lwp = RT_NULL;
  123. rt_aspace_t aspace;
  124. void *from_tbl;
  125. if (thread->lwp)
  126. {
  127. lwp = (struct rt_lwp *)thread->lwp;
  128. aspace = lwp->aspace;
  129. }
  130. else
  131. aspace = &rt_kernel_space;
  132. from_tbl = rt_hw_mmu_tbl_get();
  133. if (aspace->page_table != from_tbl)
  134. {
  135. rt_hw_aspace_switch(aspace);
  136. }
  137. }
  138. void lwp_unmap_user_space(struct rt_lwp *lwp)
  139. {
  140. arch_user_space_free(lwp);
  141. rt_free(lwp->lwp_obj);
  142. }
  143. static const char *_user_get_name(rt_varea_t varea)
  144. {
  145. char *name;
  146. if (varea->flag & MMF_TEXT)
  147. {
  148. name = "user.text";
  149. }
  150. else
  151. {
  152. if (varea->start == (void *)USER_STACK_VSTART)
  153. {
  154. name = "user.stack";
  155. }
  156. else if (varea->start >= (void *)USER_HEAP_VADDR &&
  157. varea->start < (void *)USER_HEAP_VEND)
  158. {
  159. name = "user.heap";
  160. }
  161. else
  162. {
  163. name = "user.data";
  164. }
  165. }
  166. return name;
  167. }
  168. #define NO_AUTO_FETCH 0x1
  169. #define VAREA_CAN_AUTO_FETCH(varea) (!((rt_ubase_t)((varea)->data) & NO_AUTO_FETCH))
  170. static void _user_do_page_fault(struct rt_varea *varea,
  171. struct rt_aspace_fault_msg *msg)
  172. {
  173. struct rt_lwp_objs *lwp_objs;
  174. lwp_objs = rt_container_of(varea->mem_obj, struct rt_lwp_objs, mem_obj);
  175. if (lwp_objs->source)
  176. {
  177. char *paddr = rt_hw_mmu_v2p(lwp_objs->source, msg->fault_vaddr);
  178. if (paddr != ARCH_MAP_FAILED)
  179. {
  180. void *vaddr;
  181. vaddr = paddr - PV_OFFSET;
  182. if (!(varea->flag & MMF_TEXT))
  183. {
  184. void *cp = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  185. if (cp)
  186. {
  187. memcpy(cp, vaddr, ARCH_PAGE_SIZE);
  188. rt_varea_pgmgr_insert(varea, cp);
  189. msg->response.status = MM_FAULT_STATUS_OK;
  190. msg->response.vaddr = cp;
  191. msg->response.size = ARCH_PAGE_SIZE;
  192. }
  193. else
  194. {
  195. LOG_W("%s: page alloc failed at %p", __func__,
  196. varea->start);
  197. }
  198. }
  199. else
  200. {
  201. rt_page_t page = rt_page_addr2page(vaddr);
  202. page->ref_cnt += 1;
  203. rt_varea_pgmgr_insert(varea, vaddr);
  204. msg->response.status = MM_FAULT_STATUS_OK;
  205. msg->response.vaddr = vaddr;
  206. msg->response.size = ARCH_PAGE_SIZE;
  207. }
  208. }
  209. else if (!(varea->flag & MMF_TEXT))
  210. {
  211. /* if data segment not exist in source do a fallback */
  212. rt_mm_dummy_mapper.on_page_fault(varea, msg);
  213. }
  214. }
  215. else if (VAREA_CAN_AUTO_FETCH(varea))
  216. {
  217. /* if (!lwp_objs->source), no aspace as source data */
  218. rt_mm_dummy_mapper.on_page_fault(varea, msg);
  219. }
  220. }
  221. static void _init_lwp_objs(struct rt_lwp_objs *lwp_objs, rt_aspace_t aspace)
  222. {
  223. if (lwp_objs)
  224. {
  225. /**
  226. * @brief one lwp_obj represent an base layout of page based memory in user space
  227. * This is useful on duplication. Where we only have a (lwp_objs and offset) to
  228. * provide identical memory. This is implemented by lwp_objs->source.
  229. */
  230. lwp_objs->source = NULL;
  231. memcpy(&lwp_objs->mem_obj, &rt_mm_dummy_mapper, sizeof(struct rt_mem_obj));
  232. lwp_objs->mem_obj.get_name = _user_get_name;
  233. lwp_objs->mem_obj.on_page_fault = _user_do_page_fault;
  234. }
  235. }
  236. static void *_lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size,
  237. int text)
  238. {
  239. void *va = map_va;
  240. int ret = 0;
  241. rt_size_t flags = MMF_PREFETCH;
  242. if (text)
  243. flags |= MMF_TEXT;
  244. if (va != RT_NULL)
  245. flags |= MMF_MAP_FIXED;
  246. ret = rt_aspace_map_private(lwp->aspace, &va, map_size, MMU_MAP_U_RWCB, flags);
  247. if (ret != RT_EOK)
  248. {
  249. va = RT_NULL;
  250. LOG_I("lwp_map_user: failed to map %lx with size %lx with errno %d", map_va,
  251. map_size, ret);
  252. }
  253. return va;
  254. }
  255. int lwp_unmap_user(struct rt_lwp *lwp, void *va)
  256. {
  257. int err = rt_aspace_unmap(lwp->aspace, va);
  258. return err;
  259. }
  260. /** fork the src_lwp->aspace in current */
  261. int lwp_fork_aspace(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp)
  262. {
  263. int err;
  264. err = rt_aspace_fork(&src_lwp->aspace, &dest_lwp->aspace);
  265. if (!err)
  266. {
  267. /* do a explicit aspace switch if the page table is changed */
  268. lwp_aspace_switch(rt_thread_self());
  269. }
  270. return err;
  271. }
  272. int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va)
  273. {
  274. return lwp_unmap_user(lwp, va);
  275. }
  276. void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, int text)
  277. {
  278. void *ret = RT_NULL;
  279. size_t offset = 0;
  280. if (!map_size)
  281. {
  282. return 0;
  283. }
  284. offset = (size_t)map_va & ARCH_PAGE_MASK;
  285. map_size += (offset + ARCH_PAGE_SIZE - 1);
  286. map_size &= ~ARCH_PAGE_MASK;
  287. map_va = (void *)((size_t)map_va & ~ARCH_PAGE_MASK);
  288. ret = _lwp_map_user(lwp, map_va, map_size, text);
  289. if (ret)
  290. {
  291. ret = (void *)((char *)ret + offset);
  292. }
  293. return ret;
  294. }
  295. static inline size_t _flags_to_attr(size_t flags)
  296. {
  297. size_t attr;
  298. if (flags & LWP_MAP_FLAG_NOCACHE)
  299. {
  300. attr = MMU_MAP_U_RW;
  301. }
  302. else
  303. {
  304. attr = MMU_MAP_U_RWCB;
  305. }
  306. return attr;
  307. }
  308. static inline mm_flag_t _flags_to_aspace_flag(size_t flags)
  309. {
  310. mm_flag_t mm_flag = 0;
  311. if (flags & LWP_MAP_FLAG_MAP_FIXED)
  312. mm_flag |= MMF_MAP_FIXED;
  313. if (flags & LWP_MAP_FLAG_PREFETCH)
  314. mm_flag |= MMF_PREFETCH;
  315. return mm_flag;
  316. }
  317. static rt_varea_t _lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags)
  318. {
  319. void *va = map_va;
  320. int ret = 0;
  321. rt_varea_t varea = RT_NULL;
  322. mm_flag_t mm_flags;
  323. size_t attr;
  324. attr = _flags_to_attr(flags);
  325. mm_flags = _flags_to_aspace_flag(flags);
  326. ret = rt_aspace_map_private(lwp->aspace, &va, map_size,
  327. attr, mm_flags);
  328. if (ret == RT_EOK)
  329. {
  330. varea = rt_aspace_query(lwp->aspace, va);
  331. }
  332. if (ret != RT_EOK)
  333. {
  334. LOG_I("lwp_map_user: failed to map %lx with size %lx with errno %d", map_va,
  335. map_size, ret);
  336. }
  337. return varea;
  338. }
  339. static rt_varea_t _map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags)
  340. {
  341. size_t offset = 0;
  342. if (!map_size)
  343. {
  344. return 0;
  345. }
  346. offset = (size_t)map_va & ARCH_PAGE_MASK;
  347. map_size += (offset + ARCH_PAGE_SIZE - 1);
  348. map_size &= ~ARCH_PAGE_MASK;
  349. map_va = (void *)((size_t)map_va & ~ARCH_PAGE_MASK);
  350. return _lwp_map_user_varea(lwp, map_va, map_size, flags);
  351. }
  352. rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags)
  353. {
  354. return _map_user_varea_ext(lwp, map_va, map_size, flags);
  355. }
  356. rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size)
  357. {
  358. return _map_user_varea_ext(lwp, map_va, map_size, LWP_MAP_FLAG_NONE);
  359. }
  360. void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa,
  361. size_t map_size, int cached)
  362. {
  363. int err;
  364. char *va;
  365. size_t offset = 0;
  366. if (!map_size)
  367. {
  368. return 0;
  369. }
  370. if (map_va)
  371. {
  372. if (((size_t)map_va & ARCH_PAGE_MASK) !=
  373. ((size_t)map_pa & ARCH_PAGE_MASK))
  374. {
  375. return 0;
  376. }
  377. }
  378. offset = (size_t)map_pa & ARCH_PAGE_MASK;
  379. map_size += (offset + ARCH_PAGE_SIZE - 1);
  380. map_size &= ~ARCH_PAGE_MASK;
  381. map_pa = (void *)((size_t)map_pa & ~ARCH_PAGE_MASK);
  382. struct rt_mm_va_hint hint = {.flags = 0,
  383. .limit_range_size = lwp->aspace->size,
  384. .limit_start = lwp->aspace->start,
  385. .prefer = map_va,
  386. .map_size = map_size};
  387. if (map_va != RT_NULL)
  388. hint.flags |= MMF_MAP_FIXED;
  389. rt_size_t attr = cached ? MMU_MAP_U_RWCB : MMU_MAP_U_RW;
  390. err =
  391. rt_aspace_map_phy(lwp->aspace, &hint, attr, MM_PA_TO_OFF(map_pa), (void **)&va);
  392. if (err != RT_EOK)
  393. {
  394. va = RT_NULL;
  395. LOG_W("%s", __func__);
  396. }
  397. else
  398. {
  399. va += offset;
  400. }
  401. return va;
  402. }
  403. rt_base_t lwp_brk(void *addr)
  404. {
  405. rt_base_t ret = -1;
  406. rt_varea_t varea = RT_NULL;
  407. struct rt_lwp *lwp = RT_NULL;
  408. size_t size = 0;
  409. lwp = lwp_self();
  410. if ((size_t)addr == RT_NULL)
  411. {
  412. addr = (char *)lwp->end_heap + 1;
  413. }
  414. if ((size_t)addr <= lwp->end_heap && (size_t)addr > USER_HEAP_VADDR)
  415. {
  416. ret = (size_t)addr;
  417. }
  418. else if ((size_t)addr <= USER_HEAP_VEND)
  419. {
  420. size = RT_ALIGN((size_t)addr - lwp->end_heap, ARCH_PAGE_SIZE);
  421. varea = lwp_map_user_varea_ext(lwp, (void *)lwp->end_heap, size, LWP_MAP_FLAG_PREFETCH);
  422. if (varea)
  423. {
  424. lwp->end_heap = (long)(varea->start + varea->size);
  425. ret = lwp->end_heap;
  426. }
  427. }
  428. return ret;
  429. }
  430. rt_inline rt_mem_obj_t _get_mmap_obj(struct rt_lwp *lwp)
  431. {
  432. return &_null_object;
  433. }
  434. rt_inline rt_bool_t _memory_threshold_ok(void)
  435. {
  436. #define GUARDIAN_BITS (10)
  437. size_t total, free;
  438. rt_page_get_info(&total, &free);
  439. if (free * (0x1000) < 0x100000)
  440. {
  441. LOG_I("%s: low of system memory", __func__);
  442. return RT_FALSE;
  443. }
  444. return RT_TRUE;
  445. }
  446. rt_inline long _uflag_to_kernel(long flag)
  447. {
  448. flag &= ~MMF_MAP_FIXED;
  449. flag &= ~MMF_MAP_PRIVATE;
  450. flag &= ~MMF_MAP_PRIVATE_DONT_SYNC;
  451. return flag;
  452. }
  453. rt_inline long _uattr_to_kernel(long attr)
  454. {
  455. /* Warning: be careful with the case if user attribution is unwritable */
  456. return attr;
  457. }
  458. static void _prefetch_mmap(rt_aspace_t aspace, void *addr, long size)
  459. {
  460. struct rt_aspace_fault_msg msg;
  461. msg.fault_op = MM_FAULT_OP_WRITE;
  462. msg.fault_type = MM_FAULT_TYPE_PAGE_FAULT;
  463. for (char *base = addr; size > 0; base += ARCH_PAGE_SIZE, size -= ARCH_PAGE_SIZE)
  464. {
  465. msg.fault_vaddr = base;
  466. msg.off = (long)base >> MM_PAGE_SHIFT;
  467. rt_aspace_fault_try_fix(aspace, &msg);
  468. }
  469. return ;
  470. }
  471. void *lwp_user_memory_remap_to_kernel(rt_lwp_t lwp, void *uaddr, size_t length)
  472. {
  473. long kattr;
  474. long kflag;
  475. long offset_in_mobj;
  476. long offset_in_page;
  477. rt_err_t error;
  478. rt_varea_t uarea;
  479. rt_mem_obj_t mobj;
  480. void *kaddr = 0;
  481. uarea = rt_aspace_query(lwp->aspace, uaddr);
  482. if (uarea)
  483. {
  484. /* setup the identical mapping, and align up for address & length */
  485. kattr = _uattr_to_kernel(uarea->attr);
  486. kflag = _uflag_to_kernel(uarea->flag);
  487. offset_in_mobj = uarea->offset + ((long)uaddr - (long)uarea->start) / ARCH_PAGE_SIZE;
  488. mobj = uarea->mem_obj;
  489. offset_in_page = (long)uaddr & ARCH_PAGE_MASK;
  490. length = RT_ALIGN(length + offset_in_page, ARCH_PAGE_SIZE);
  491. error = rt_aspace_map(&rt_kernel_space, &kaddr, length, kattr, kflag, mobj, offset_in_mobj);
  492. if (error)
  493. {
  494. LOG_I("%s(length=0x%lx,attr=0x%lx,flags=0x%lx): do map failed", __func__, length, kattr, kflag);
  495. kaddr = 0;
  496. }
  497. else
  498. {
  499. /* TODO: {make a memory lock?} */
  500. LOG_D("%s(length=0x%lx,attr=0x%lx,flags=0x%lx,offset=0x%lx) => %p", __func__, length, kattr, kflag, offset_in_mobj, kaddr);
  501. _prefetch_mmap(&rt_kernel_space, kaddr, length);
  502. kaddr += offset_in_page;
  503. }
  504. }
  505. return kaddr;
  506. }
  507. void *lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot,
  508. int flags, int fd, off_t pgoffset)
  509. {
  510. rt_err_t rc;
  511. rt_size_t k_attr;
  512. rt_size_t k_flags;
  513. rt_size_t k_offset;
  514. rt_aspace_t uspace;
  515. rt_mem_obj_t mem_obj;
  516. void *ret = 0;
  517. LOG_D("%s(addr=0x%lx,length=%ld,fd=%d)", __func__, addr, length, fd);
  518. if (fd == -1)
  519. {
  520. /**
  521. * todo: add threshold
  522. */
  523. if (!_memory_threshold_ok())
  524. return (void *)-ENOMEM;
  525. k_offset = MM_PA_TO_OFF(addr);
  526. k_flags = lwp_user_mm_flag_to_kernel(flags) | MMF_MAP_PRIVATE;
  527. k_attr = lwp_user_mm_attr_to_kernel(prot);
  528. uspace = lwp->aspace;
  529. length = RT_ALIGN(length, ARCH_PAGE_SIZE);
  530. mem_obj = _get_mmap_obj(lwp);
  531. rc = rt_aspace_map(uspace, &addr, length, k_attr, k_flags, mem_obj, k_offset);
  532. if (rc == RT_EOK)
  533. {
  534. ret = addr;
  535. }
  536. else
  537. {
  538. ret = (void *)lwp_errno_to_posix(rc);
  539. }
  540. }
  541. else
  542. {
  543. struct dfs_file *d;
  544. d = fd_get(fd);
  545. if (d)
  546. {
  547. struct dfs_mmap2_args mmap2;
  548. mmap2.addr = addr;
  549. mmap2.length = length;
  550. mmap2.prot = prot;
  551. mmap2.flags = flags;
  552. mmap2.pgoffset = pgoffset;
  553. mmap2.ret = (void *)-1;
  554. mmap2.lwp = lwp;
  555. rc = dfs_file_mmap2(d, &mmap2);
  556. if (rc == RT_EOK)
  557. {
  558. ret = mmap2.ret;
  559. }
  560. else
  561. {
  562. ret = (void *)lwp_errno_to_posix(rc);
  563. }
  564. }
  565. }
  566. if ((long)ret <= 0)
  567. LOG_D("%s() => %ld", __func__, ret);
  568. return ret;
  569. }
  570. int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length)
  571. {
  572. int ret;
  573. RT_ASSERT(lwp);
  574. ret = rt_aspace_unmap_range(lwp->aspace, addr, length);
  575. return lwp_errno_to_posix(ret);
  576. }
  577. size_t lwp_get_from_user(void *dst, void *src, size_t size)
  578. {
  579. struct rt_lwp *lwp = RT_NULL;
  580. /* check src */
  581. if (src < (void *)USER_VADDR_START)
  582. {
  583. return 0;
  584. }
  585. if (src >= (void *)USER_VADDR_TOP)
  586. {
  587. return 0;
  588. }
  589. if ((void *)((char *)src + size) > (void *)USER_VADDR_TOP)
  590. {
  591. return 0;
  592. }
  593. lwp = lwp_self();
  594. if (!lwp)
  595. {
  596. return 0;
  597. }
  598. return lwp_data_get(lwp, dst, src, size);
  599. }
  600. size_t lwp_put_to_user(void *dst, void *src, size_t size)
  601. {
  602. struct rt_lwp *lwp = RT_NULL;
  603. /* check dst */
  604. if (dst < (void *)USER_VADDR_START)
  605. {
  606. return 0;
  607. }
  608. if (dst >= (void *)USER_VADDR_TOP)
  609. {
  610. return 0;
  611. }
  612. if ((void *)((char *)dst + size) > (void *)USER_VADDR_TOP)
  613. {
  614. return 0;
  615. }
  616. lwp = lwp_self();
  617. if (!lwp)
  618. {
  619. return 0;
  620. }
  621. return lwp_data_put(lwp, dst, src, size);
  622. }
  623. rt_inline rt_bool_t _in_user_space(const char *addr)
  624. {
  625. return (addr >= (char *)USER_VADDR_START && addr < (char *)USER_VADDR_TOP);
  626. }
  627. rt_inline rt_bool_t _can_unaligned_access(const char *addr)
  628. {
  629. return rt_kmem_v2p((char *)addr) - PV_OFFSET == addr;
  630. }
  631. void *lwp_memcpy(void * __restrict dst, const void * __restrict src, size_t size)
  632. {
  633. void *rc = dst;
  634. long len;
  635. if (_in_user_space(dst))
  636. {
  637. if (!_in_user_space(src))
  638. {
  639. len = lwp_put_to_user(dst, (void *)src, size);
  640. if (!len)
  641. {
  642. LOG_E("lwp_put_to_user(lwp=%p, dst=%p,src=%p,size=0x%lx) failed", lwp_self(), dst, src, size);
  643. }
  644. }
  645. else
  646. {
  647. /* not support yet */
  648. LOG_W("%s(dst=%p,src=%p,size=0x%lx): operation not support", dst, src, size, __func__);
  649. }
  650. }
  651. else
  652. {
  653. if (_in_user_space(src))
  654. {
  655. len = lwp_get_from_user(dst, (void *)src, size);
  656. if (!len)
  657. {
  658. LOG_E("lwp_get_from_user(lwp=%p, dst=%p,src=%p,size=0x%lx) failed", lwp_self(), dst, src, size);
  659. }
  660. }
  661. else
  662. {
  663. if (_can_unaligned_access(dst) && _can_unaligned_access(src))
  664. {
  665. rc = memcpy(dst, src, size);
  666. }
  667. else
  668. {
  669. rt_memcpy(dst, src, size);
  670. }
  671. }
  672. }
  673. return rc;
  674. }
  675. int lwp_user_accessible_ext(struct rt_lwp *lwp, void *addr, size_t size)
  676. {
  677. void *addr_start = RT_NULL, *addr_end = RT_NULL, *next_page = RT_NULL;
  678. void *tmp_addr = RT_NULL;
  679. if (!lwp)
  680. {
  681. return RT_FALSE;
  682. }
  683. if (!size || !addr)
  684. {
  685. return RT_FALSE;
  686. }
  687. addr_start = addr;
  688. addr_end = (void *)((char *)addr + size);
  689. #ifdef ARCH_RISCV64
  690. if (addr_start < (void *)USER_VADDR_START)
  691. {
  692. return RT_FALSE;
  693. }
  694. #else
  695. if (addr_start >= (void *)USER_VADDR_TOP)
  696. {
  697. return RT_FALSE;
  698. }
  699. if (addr_end > (void *)USER_VADDR_TOP)
  700. {
  701. return RT_FALSE;
  702. }
  703. #endif
  704. next_page =
  705. (void *)(((size_t)addr_start + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
  706. do
  707. {
  708. size_t len = (char *)next_page - (char *)addr_start;
  709. if (size < len)
  710. {
  711. len = size;
  712. }
  713. tmp_addr = lwp_v2p(lwp, addr_start);
  714. if (tmp_addr == ARCH_MAP_FAILED &&
  715. !rt_aspace_query(lwp->aspace, addr_start))
  716. {
  717. return RT_FALSE;
  718. }
  719. addr_start = (void *)((char *)addr_start + len);
  720. size -= len;
  721. next_page = (void *)((char *)next_page + ARCH_PAGE_SIZE);
  722. } while (addr_start < addr_end);
  723. return RT_TRUE;
  724. }
  725. int lwp_user_accessable(void *addr, size_t size)
  726. {
  727. return lwp_user_accessible_ext(lwp_self(), addr, size);
  728. }
  729. #define ALIGNED(addr) (!((rt_size_t)(addr) & ARCH_PAGE_MASK))
  730. /* src is in lwp address space, dst is in current thread space */
  731. size_t lwp_data_get(struct rt_lwp *lwp, void *dst, void *src, size_t size)
  732. {
  733. size_t copy_len = 0;
  734. char *temp_page = 0;
  735. char *dst_iter, *dst_next_page;
  736. char *src_copy_end, *src_iter, *src_iter_aligned;
  737. if (!size || !dst)
  738. {
  739. return 0;
  740. }
  741. dst_iter = dst;
  742. src_iter = src;
  743. src_copy_end = src + size;
  744. dst_next_page =
  745. (char *)(((size_t)src_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
  746. do
  747. {
  748. size_t bytes_to_copy = (char *)dst_next_page - (char *)src_iter;
  749. if (bytes_to_copy > size)
  750. {
  751. bytes_to_copy = size;
  752. }
  753. if (ALIGNED(src_iter) && bytes_to_copy == ARCH_PAGE_SIZE)
  754. {
  755. /* get page to kernel buffer */
  756. if (rt_aspace_page_get(lwp->aspace, src_iter, dst_iter))
  757. break;
  758. }
  759. else
  760. {
  761. if (!temp_page)
  762. temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  763. if (!temp_page)
  764. break;
  765. src_iter_aligned = (char *)((long)src_iter & ~ARCH_PAGE_MASK);
  766. if (rt_aspace_page_get(lwp->aspace, src_iter_aligned, temp_page))
  767. break;
  768. memcpy(dst_iter, temp_page + (src_iter - src_iter_aligned), bytes_to_copy);
  769. }
  770. dst_iter = dst_iter + bytes_to_copy;
  771. src_iter = src_iter + bytes_to_copy;
  772. size -= bytes_to_copy;
  773. dst_next_page = (void *)((char *)dst_next_page + ARCH_PAGE_SIZE);
  774. copy_len += bytes_to_copy;
  775. } while (src_iter < src_copy_end);
  776. if (temp_page)
  777. rt_pages_free(temp_page, 0);
  778. return copy_len;
  779. }
  780. /* dst is in lwp address space, src is in current thread space */
  781. size_t lwp_data_put(struct rt_lwp *lwp, void *dst, void *src, size_t size)
  782. {
  783. size_t copy_len = 0;
  784. char *temp_page = 0;
  785. char *dst_iter, *dst_iter_aligned, *dst_next_page;
  786. char *src_put_end, *src_iter;
  787. if (!size || !dst)
  788. {
  789. return 0;
  790. }
  791. src_iter = src;
  792. dst_iter = dst;
  793. src_put_end = dst + size;
  794. dst_next_page =
  795. (char *)(((size_t)dst_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
  796. do
  797. {
  798. size_t bytes_to_put = (char *)dst_next_page - (char *)dst_iter;
  799. if (bytes_to_put > size)
  800. {
  801. bytes_to_put = size;
  802. }
  803. if (ALIGNED(dst_iter) && bytes_to_put == ARCH_PAGE_SIZE)
  804. {
  805. /* write to page in kernel */
  806. if (rt_aspace_page_put(lwp->aspace, dst_iter, src_iter))
  807. break;
  808. }
  809. else
  810. {
  811. if (!temp_page)
  812. temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  813. if (!temp_page)
  814. break;
  815. dst_iter_aligned = (void *)((long)dst_iter & ~ARCH_PAGE_MASK);
  816. if (rt_aspace_page_get(lwp->aspace, dst_iter_aligned, temp_page))
  817. break;
  818. memcpy(temp_page + (dst_iter - dst_iter_aligned), src_iter, bytes_to_put);
  819. if (rt_aspace_page_put(lwp->aspace, dst_iter_aligned, temp_page))
  820. break;
  821. }
  822. src_iter = src_iter + bytes_to_put;
  823. dst_iter = dst_iter + bytes_to_put;
  824. size -= bytes_to_put;
  825. dst_next_page = dst_next_page + ARCH_PAGE_SIZE;
  826. copy_len += bytes_to_put;
  827. } while (dst_iter < src_put_end);
  828. if (temp_page)
  829. rt_pages_free(temp_page, 0);
  830. return copy_len;
  831. }
  832. /* Set N bytes of S to C */
  833. size_t lwp_data_set(struct rt_lwp *lwp, void *dst, int byte, size_t size)
  834. {
  835. size_t copy_len = 0;
  836. char *temp_page = 0;
  837. char *dst_iter, *dst_iter_aligned, *dst_next_page;
  838. char *dst_put_end;
  839. if (!size || !dst)
  840. {
  841. return 0;
  842. }
  843. dst_iter = dst;
  844. dst_put_end = dst + size;
  845. dst_next_page =
  846. (char *)(((size_t)dst_iter + ARCH_PAGE_SIZE) & ~(ARCH_PAGE_SIZE - 1));
  847. temp_page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  848. if (temp_page)
  849. {
  850. do
  851. {
  852. size_t bytes_to_put = (char *)dst_next_page - (char *)dst_iter;
  853. if (bytes_to_put > size)
  854. {
  855. bytes_to_put = size;
  856. }
  857. dst_iter_aligned = (void *)((long)dst_iter & ~ARCH_PAGE_MASK);
  858. if (!ALIGNED(dst_iter) || bytes_to_put != ARCH_PAGE_SIZE)
  859. if (rt_aspace_page_get(lwp->aspace, dst_iter_aligned, temp_page))
  860. break;
  861. memset(temp_page + (dst_iter - dst_iter_aligned), byte, bytes_to_put);
  862. if (rt_aspace_page_put(lwp->aspace, dst_iter_aligned, temp_page))
  863. break;
  864. dst_iter = dst_iter + bytes_to_put;
  865. size -= bytes_to_put;
  866. dst_next_page = dst_next_page + ARCH_PAGE_SIZE;
  867. copy_len += bytes_to_put;
  868. } while (dst_iter < dst_put_end);
  869. rt_pages_free(temp_page, 0);
  870. }
  871. return copy_len;
  872. }
  873. size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s)
  874. {
  875. int len = 0;
  876. char *temp_buf = RT_NULL;
  877. void *addr_start = RT_NULL;
  878. int get_bytes = 0;
  879. int index = 0;
  880. if (s == RT_NULL)
  881. return 0;
  882. if (lwp == RT_NULL)
  883. {
  884. LOG_W("%s: lwp is NULL", __func__);
  885. return -1;
  886. }
  887. addr_start = (void *)s;
  888. temp_buf = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
  889. if (!temp_buf)
  890. {
  891. LOG_W("%s: No memory", __func__);
  892. return -1;
  893. }
  894. get_bytes = lwp_data_get(lwp, temp_buf, addr_start, ARCH_PAGE_SIZE);
  895. if (get_bytes == 0)
  896. {
  897. LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000) failed", lwp, temp_buf, addr_start);
  898. rt_pages_free(temp_buf, 0);
  899. return -1;
  900. }
  901. while (temp_buf[index] != '\0')
  902. {
  903. len++;
  904. index++;
  905. if (index == get_bytes)
  906. {
  907. if (get_bytes == ARCH_PAGE_SIZE)
  908. {
  909. get_bytes = lwp_data_get(lwp, temp_buf, addr_start + len, ARCH_PAGE_SIZE);
  910. if (get_bytes == 0)
  911. {
  912. LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000): user data unaccessible",
  913. lwp, temp_buf, addr_start);
  914. len = -1;
  915. break;
  916. }
  917. index = 0;
  918. }
  919. else
  920. {
  921. LOG_I("lwp_data_get(lwp=%p,dst=0x%lx,src=0x%lx,size=0x1000): user data unaccessible",
  922. lwp, temp_buf, addr_start);
  923. len = -1;
  924. break;
  925. }
  926. }
  927. }
  928. rt_pages_free(temp_buf, 0);
  929. return len;
  930. }
  931. size_t lwp_user_strlen(const char *s)
  932. {
  933. struct rt_lwp *lwp = RT_NULL;
  934. lwp = lwp_self();
  935. RT_ASSERT(lwp != RT_NULL);
  936. return lwp_user_strlen_ext(lwp, s);
  937. }
  938. char** lwp_get_command_line_args(struct rt_lwp *lwp)
  939. {
  940. size_t argc = 0;
  941. char** argv = NULL;
  942. int ret;
  943. size_t i;
  944. size_t len;
  945. if (lwp)
  946. {
  947. ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
  948. if (ret == 0)
  949. {
  950. return RT_NULL;
  951. }
  952. argv = (char**)rt_malloc((argc + 1) * sizeof(char*));
  953. if (argv)
  954. {
  955. for (i = 0; i < argc; i++)
  956. {
  957. char *argvp = NULL;
  958. ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
  959. if (ret == 0)
  960. {
  961. lwp_free_command_line_args(argv);
  962. return RT_NULL;
  963. }
  964. len = lwp_user_strlen_ext(lwp, argvp);
  965. if (len > 0)
  966. {
  967. argv[i] = (char*)rt_malloc(len + 1);
  968. ret = lwp_data_get(lwp, argv[i], argvp, len);
  969. if (ret == 0)
  970. {
  971. lwp_free_command_line_args(argv);
  972. return RT_NULL;
  973. }
  974. argv[i][len] = '\0';
  975. }
  976. else
  977. {
  978. argv[i] = NULL;
  979. }
  980. }
  981. argv[argc] = NULL;
  982. }
  983. }
  984. return argv;
  985. }
  986. void lwp_free_command_line_args(char** argv)
  987. {
  988. size_t i;
  989. if (argv)
  990. {
  991. for (i = 0; argv[i]; i++)
  992. {
  993. rt_free(argv[i]);
  994. }
  995. rt_free(argv);
  996. }
  997. }
  998. #endif