mali_mmu_page_directory.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /*
  2. * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
  3. *
  4. * This program is free software and is provided to you under the terms of the GNU General Public License version 2
  5. * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
  6. *
  7. * A copy of the licence is included with the program, and can also be obtained from Free Software
  8. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  9. */
  10. #include "mali_kernel_common.h"
  11. #include "mali_kernel_core.h"
  12. #include "mali_osk.h"
  13. #include "mali_uk_types.h"
  14. #include "mali_mmu_page_directory.h"
  15. #include "mali_memory.h"
  16. #include "mali_cluster.h"
  17. #include "mali_group.h"
  18. static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data);
  19. u32 mali_allocate_empty_page(void)
  20. {
  21. _mali_osk_errcode_t err;
  22. mali_io_address mapping;
  23. u32 address;
  24. if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&address, &mapping))
  25. {
  26. /* Allocation failed */
  27. return 0;
  28. }
  29. MALI_DEBUG_ASSERT_POINTER( mapping );
  30. err = fill_page(mapping, 0);
  31. if (_MALI_OSK_ERR_OK != err)
  32. {
  33. mali_mmu_release_table_page(address);
  34. }
  35. return address;
  36. }
  37. void mali_free_empty_page(u32 address)
  38. {
  39. if (MALI_INVALID_PAGE != address)
  40. {
  41. mali_mmu_release_table_page(address);
  42. }
  43. }
  44. _mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page)
  45. {
  46. _mali_osk_errcode_t err;
  47. mali_io_address page_directory_mapping;
  48. mali_io_address page_table_mapping;
  49. mali_io_address data_page_mapping;
  50. err = mali_mmu_get_table_page(data_page, &data_page_mapping);
  51. if (_MALI_OSK_ERR_OK == err)
  52. {
  53. err = mali_mmu_get_table_page(page_table, &page_table_mapping);
  54. if (_MALI_OSK_ERR_OK == err)
  55. {
  56. err = mali_mmu_get_table_page(page_directory, &page_directory_mapping);
  57. if (_MALI_OSK_ERR_OK == err)
  58. {
  59. fill_page(data_page_mapping, 0);
  60. fill_page(page_table_mapping, *data_page | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT);
  61. fill_page(page_directory_mapping, *page_table | MALI_MMU_FLAGS_PRESENT);
  62. MALI_SUCCESS;
  63. }
  64. mali_mmu_release_table_page(*page_table);
  65. *page_table = MALI_INVALID_PAGE;
  66. }
  67. mali_mmu_release_table_page(*data_page);
  68. *data_page = MALI_INVALID_PAGE;
  69. }
  70. return err;
  71. }
  72. void mali_destroy_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page)
  73. {
  74. if (MALI_INVALID_PAGE != *page_directory)
  75. {
  76. mali_mmu_release_table_page(*page_directory);
  77. *page_directory = MALI_INVALID_PAGE;
  78. }
  79. if (MALI_INVALID_PAGE != *page_table)
  80. {
  81. mali_mmu_release_table_page(*page_table);
  82. *page_table = MALI_INVALID_PAGE;
  83. }
  84. if (MALI_INVALID_PAGE != *data_page)
  85. {
  86. mali_mmu_release_table_page(*data_page);
  87. *data_page = MALI_INVALID_PAGE;
  88. }
  89. }
  90. static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data)
  91. {
  92. int i;
  93. MALI_DEBUG_ASSERT_POINTER( mapping );
  94. for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++)
  95. {
  96. _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data);
  97. }
  98. _mali_osk_mem_barrier();
  99. MALI_SUCCESS;
  100. }
  101. _mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size)
  102. {
  103. const int first_pde = MALI_MMU_PDE_ENTRY(mali_address);
  104. const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1);
  105. _mali_osk_errcode_t err;
  106. mali_io_address pde_mapping;
  107. u32 pde_phys;
  108. int i;
  109. for(i = first_pde; i <= last_pde; i++)
  110. {
  111. if(0 == (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & MALI_MMU_FLAGS_PRESENT))
  112. {
  113. /* Page table not present */
  114. MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]);
  115. MALI_DEBUG_ASSERT(NULL == pagedir->page_entries_mapped[i]);
  116. err = mali_mmu_get_table_page(&pde_phys, &pde_mapping);
  117. if(_MALI_OSK_ERR_OK != err)
  118. {
  119. MALI_PRINT_ERROR(("Failed to allocate page table page.\n"));
  120. return err;
  121. }
  122. pagedir->page_entries_mapped[i] = pde_mapping;
  123. /* Update PDE, mark as present */
  124. _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32),
  125. pde_phys | MALI_MMU_FLAGS_PRESENT);
  126. MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]);
  127. pagedir->page_entries_usage_count[i] = 1;
  128. }
  129. else
  130. {
  131. pagedir->page_entries_usage_count[i]++;
  132. }
  133. }
  134. _mali_osk_write_mem_barrier();
  135. MALI_SUCCESS;
  136. }
  137. MALI_STATIC_INLINE void mali_mmu_zero_pte(mali_io_address page_table, u32 mali_address, u32 size)
  138. {
  139. int i;
  140. const int first_pte = MALI_MMU_PTE_ENTRY(mali_address);
  141. const int last_pte = MALI_MMU_PTE_ENTRY(mali_address + size - 1);
  142. for (i = first_pte; i <= last_pte; i++)
  143. {
  144. _mali_osk_mem_iowrite32_relaxed(page_table, i * sizeof(u32), 0);
  145. }
  146. }
  147. _mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size)
  148. {
  149. const int first_pde = MALI_MMU_PDE_ENTRY(mali_address);
  150. const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1);
  151. u32 left = size;
  152. int i;
  153. #ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2
  154. mali_bool pd_changed = MALI_FALSE;
  155. u32 pages_to_invalidate[3]; /* hard-coded to 3: max two pages from the PT level plus max one page from PD level */
  156. u32 num_pages_inv = 0;
  157. #endif
  158. /* For all page directory entries in range. */
  159. for (i = first_pde; i <= last_pde; i++)
  160. {
  161. u32 size_in_pde, offset;
  162. MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[i]);
  163. MALI_DEBUG_ASSERT(0 != pagedir->page_entries_usage_count[i]);
  164. /* Offset into page table, 0 if mali_address is 4MiB aligned */
  165. offset = (mali_address & (MALI_MMU_VIRTUAL_PAGE_SIZE - 1));
  166. if (left < MALI_MMU_VIRTUAL_PAGE_SIZE - offset)
  167. {
  168. size_in_pde = left;
  169. }
  170. else
  171. {
  172. size_in_pde = MALI_MMU_VIRTUAL_PAGE_SIZE - offset;
  173. }
  174. pagedir->page_entries_usage_count[i]--;
  175. /* If entire page table is unused, free it */
  176. if (0 == pagedir->page_entries_usage_count[i])
  177. {
  178. u32 page_address;
  179. MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n"));
  180. /* last reference removed, no need to zero out each PTE */
  181. page_address = MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)));
  182. pagedir->page_entries_mapped[i] = NULL;
  183. _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), 0);
  184. mali_mmu_release_table_page(page_address);
  185. #ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2
  186. pd_changed = MALI_TRUE;
  187. #endif
  188. }
  189. else
  190. {
  191. #ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2
  192. pages_to_invalidate[num_pages_inv] = mali_page_directory_get_phys_address(pagedir, i);
  193. num_pages_inv++;
  194. MALI_DEBUG_ASSERT(num_pages_inv<3);
  195. #endif
  196. /* If part of the page table is still in use, zero the relevant PTEs */
  197. mali_mmu_zero_pte(pagedir->page_entries_mapped[i], mali_address, size_in_pde);
  198. }
  199. left -= size_in_pde;
  200. mali_address += size_in_pde;
  201. }
  202. _mali_osk_write_mem_barrier();
  203. #ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2
  204. /* L2 pages invalidation */
  205. if (MALI_TRUE == pd_changed)
  206. {
  207. pages_to_invalidate[num_pages_inv] = pagedir->page_directory;
  208. num_pages_inv++;
  209. MALI_DEBUG_ASSERT(num_pages_inv<3);
  210. }
  211. if (_MALI_PRODUCT_ID_MALI200 != mali_kernel_core_get_product_id())
  212. {
  213. mali_cluster_invalidate_pages(pages_to_invalidate, num_pages_inv);
  214. }
  215. #endif
  216. MALI_SUCCESS;
  217. }
  218. struct mali_page_directory *mali_mmu_pagedir_alloc(void)
  219. {
  220. struct mali_page_directory *pagedir;
  221. pagedir = _mali_osk_calloc(1, sizeof(struct mali_page_directory));
  222. if(NULL == pagedir)
  223. {
  224. return NULL;
  225. }
  226. if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&pagedir->page_directory, &pagedir->page_directory_mapped))
  227. {
  228. _mali_osk_free(pagedir);
  229. return NULL;
  230. }
  231. /* Zero page directory */
  232. fill_page(pagedir->page_directory_mapped, 0);
  233. return pagedir;
  234. }
  235. void mali_mmu_pagedir_free(struct mali_page_directory *pagedir)
  236. {
  237. const int num_page_table_entries = sizeof(pagedir->page_entries_mapped) / sizeof(pagedir->page_entries_mapped[0]);
  238. int i;
  239. /* Free referenced page tables and zero PDEs. */
  240. for (i = 0; i < num_page_table_entries; i++)
  241. {
  242. if (pagedir->page_directory_mapped && (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT))
  243. {
  244. mali_mmu_release_table_page( _mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK);
  245. _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i * sizeof(u32), 0);
  246. }
  247. }
  248. _mali_osk_write_mem_barrier();
  249. /* Free the page directory page. */
  250. mali_mmu_release_table_page(pagedir->page_directory);
  251. _mali_osk_free(pagedir);
  252. }
  253. void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size)
  254. {
  255. u32 end_address = mali_address + size;
  256. /* Map physical pages into MMU page tables */
  257. for ( ; mali_address < end_address; mali_address += MALI_MMU_PAGE_SIZE, phys_address += MALI_MMU_PAGE_SIZE)
  258. {
  259. MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]);
  260. _mali_osk_mem_iowrite32_relaxed(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)],
  261. MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32),
  262. phys_address | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT);
  263. }
  264. _mali_osk_write_mem_barrier();
  265. }
  266. u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index)
  267. {
  268. return (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, index*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK);
  269. }
  270. /* For instrumented */
  271. struct dump_info
  272. {
  273. u32 buffer_left;
  274. u32 register_writes_size;
  275. u32 page_table_dump_size;
  276. u32 *buffer;
  277. };
  278. static _mali_osk_errcode_t writereg(u32 where, u32 what, const char *comment, struct dump_info *info)
  279. {
  280. if (NULL != info)
  281. {
  282. info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */
  283. if (NULL != info->buffer)
  284. {
  285. /* check that we have enough space */
  286. if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM);
  287. *info->buffer = where;
  288. info->buffer++;
  289. *info->buffer = what;
  290. info->buffer++;
  291. info->buffer_left -= sizeof(u32)*2;
  292. }
  293. }
  294. MALI_SUCCESS;
  295. }
  296. static _mali_osk_errcode_t dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info)
  297. {
  298. if (NULL != info)
  299. {
  300. /* 4096 for the page and 4 bytes for the address */
  301. const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4;
  302. const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE;
  303. const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4;
  304. info->page_table_dump_size += dump_size_in_bytes;
  305. if (NULL != info->buffer)
  306. {
  307. if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM);
  308. *info->buffer = phys_addr;
  309. info->buffer++;
  310. _mali_osk_memcpy(info->buffer, page, page_size_in_bytes);
  311. info->buffer += page_size_in_elements;
  312. info->buffer_left -= dump_size_in_bytes;
  313. }
  314. }
  315. MALI_SUCCESS;
  316. }
  317. static _mali_osk_errcode_t dump_mmu_page_table(struct mali_page_directory *pagedir, struct dump_info * info)
  318. {
  319. MALI_DEBUG_ASSERT_POINTER(pagedir);
  320. MALI_DEBUG_ASSERT_POINTER(info);
  321. if (NULL != pagedir->page_directory_mapped)
  322. {
  323. int i;
  324. MALI_CHECK_NO_ERROR(
  325. dump_page(pagedir->page_directory_mapped, pagedir->page_directory, info)
  326. );
  327. for (i = 0; i < 1024; i++)
  328. {
  329. if (NULL != pagedir->page_entries_mapped[i])
  330. {
  331. MALI_CHECK_NO_ERROR(
  332. dump_page(pagedir->page_entries_mapped[i],
  333. _mali_osk_mem_ioread32(pagedir->page_directory_mapped,
  334. i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info)
  335. );
  336. }
  337. }
  338. }
  339. MALI_SUCCESS;
  340. }
  341. static _mali_osk_errcode_t dump_mmu_registers(struct mali_page_directory *pagedir, struct dump_info * info)
  342. {
  343. MALI_CHECK_NO_ERROR(writereg(0x00000000, pagedir->page_directory,
  344. "set the page directory address", info));
  345. MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info));
  346. MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info));
  347. MALI_SUCCESS;
  348. }
  349. _mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args )
  350. {
  351. struct dump_info info = { 0, 0, 0, NULL };
  352. struct mali_session_data * session_data;
  353. MALI_DEBUG_ASSERT_POINTER(args);
  354. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  355. session_data = (struct mali_session_data *)(args->ctx);
  356. MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info));
  357. MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info));
  358. args->size = info.register_writes_size + info.page_table_dump_size;
  359. MALI_SUCCESS;
  360. }
  361. _mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args )
  362. {
  363. struct dump_info info = { 0, 0, 0, NULL };
  364. struct mali_session_data * session_data;
  365. MALI_DEBUG_ASSERT_POINTER(args);
  366. MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
  367. MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS);
  368. session_data = (struct mali_session_data *)(args->ctx);
  369. info.buffer_left = args->size;
  370. info.buffer = args->buffer;
  371. args->register_writes = info.buffer;
  372. MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info));
  373. args->page_table_dump = info.buffer;
  374. MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info));
  375. args->register_writes_size = info.register_writes_size;
  376. args->page_table_dump_size = info.page_table_dump_size;
  377. MALI_SUCCESS;
  378. }