You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

433 lines
12 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2016 by Matthias Welwarsky *
  3. * matthias.welwarsky@sysgo.com *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  17. ***************************************************************************/
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "armv8_cache.h"
  22. #include "armv8_dpm.h"
  23. #include "armv8_opcodes.h"
  24. /* CLIDR cache types */
  25. #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4
  26. #define CACHE_LEVEL_HAS_D_CACHE 0x2
  27. #define CACHE_LEVEL_HAS_I_CACHE 0x1
  28. static int armv8_d_cache_sanity_check(struct armv8_common *armv8)
  29. {
  30. struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
  31. if (armv8_cache->d_u_cache_enabled)
  32. return ERROR_OK;
  33. return ERROR_TARGET_INVALID;
  34. }
  35. static int armv8_i_cache_sanity_check(struct armv8_common *armv8)
  36. {
  37. struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
  38. if (armv8_cache->i_cache_enabled)
  39. return ERROR_OK;
  40. return ERROR_TARGET_INVALID;
  41. }
  42. static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct armv8_cachesize *size, int cl)
  43. {
  44. struct arm_dpm *dpm = armv8->arm.dpm;
  45. int retval = ERROR_OK;
  46. int32_t c_way, c_index = size->index;
  47. LOG_DEBUG("cl %" PRId32, cl);
  48. do {
  49. c_way = size->way;
  50. do {
  51. uint32_t value = (c_index << size->index_shift)
  52. | (c_way << size->way_shift) | (cl << 1);
  53. /*
  54. * DC CISW - Clean and invalidate data cache
  55. * line by Set/Way.
  56. */
  57. retval = dpm->instr_write_data_r0(dpm,
  58. armv8_opcode(armv8, ARMV8_OPC_DCCISW), value);
  59. if (retval != ERROR_OK)
  60. goto done;
  61. c_way -= 1;
  62. } while (c_way >= 0);
  63. c_index -= 1;
  64. } while (c_index >= 0);
  65. done:
  66. return retval;
  67. }
  68. static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8)
  69. {
  70. struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
  71. struct arm_dpm *dpm = armv8->arm.dpm;
  72. int cl;
  73. int retval;
  74. retval = armv8_d_cache_sanity_check(armv8);
  75. if (retval != ERROR_OK)
  76. return retval;
  77. retval = dpm->prepare(dpm);
  78. if (retval != ERROR_OK)
  79. goto done;
  80. for (cl = 0; cl < cache->loc; cl++) {
  81. /* skip i-only caches */
  82. if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
  83. continue;
  84. armv8_cache_d_inner_flush_level(armv8, &cache->arch[cl].d_u_size, cl);
  85. }
  86. retval = dpm->finish(dpm);
  87. return retval;
  88. done:
  89. LOG_ERROR("clean invalidate failed");
  90. dpm->finish(dpm);
  91. return retval;
  92. }
  93. int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
  94. {
  95. struct arm_dpm *dpm = armv8->arm.dpm;
  96. struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
  97. uint64_t linelen = armv8_cache->dminline;
  98. target_addr_t va_line, va_end;
  99. int retval;
  100. retval = armv8_d_cache_sanity_check(armv8);
  101. if (retval != ERROR_OK)
  102. return retval;
  103. retval = dpm->prepare(dpm);
  104. if (retval != ERROR_OK)
  105. goto done;
  106. va_line = va & (-linelen);
  107. va_end = va + size;
  108. while (va_line < va_end) {
  109. /* DC CIVAC */
  110. /* Aarch32: DCCIMVAC: ARMV4_5_MCR(15, 0, 0, 7, 14, 1) */
  111. retval = dpm->instr_write_data_r0_64(dpm,
  112. armv8_opcode(armv8, ARMV8_OPC_DCCIVAC), va_line);
  113. if (retval != ERROR_OK)
  114. goto done;
  115. va_line += linelen;
  116. }
  117. dpm->finish(dpm);
  118. return retval;
  119. done:
  120. LOG_ERROR("d-cache invalidate failed");
  121. dpm->finish(dpm);
  122. return retval;
  123. }
  124. int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
  125. {
  126. struct arm_dpm *dpm = armv8->arm.dpm;
  127. struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
  128. uint64_t linelen = armv8_cache->iminline;
  129. target_addr_t va_line, va_end;
  130. int retval;
  131. retval = armv8_i_cache_sanity_check(armv8);
  132. if (retval != ERROR_OK)
  133. return retval;
  134. retval = dpm->prepare(dpm);
  135. if (retval != ERROR_OK)
  136. goto done;
  137. va_line = va & (-linelen);
  138. va_end = va + size;
  139. while (va_line < va_end) {
  140. /* IC IVAU - Invalidate instruction cache by VA to PoU. */
  141. retval = dpm->instr_write_data_r0_64(dpm,
  142. armv8_opcode(armv8, ARMV8_OPC_ICIVAU), va_line);
  143. if (retval != ERROR_OK)
  144. goto done;
  145. va_line += linelen;
  146. }
  147. dpm->finish(dpm);
  148. return retval;
  149. done:
  150. LOG_ERROR("d-cache invalidate failed");
  151. dpm->finish(dpm);
  152. return retval;
  153. }
  154. static int armv8_handle_inner_cache_info_command(struct command_invocation *cmd,
  155. struct armv8_cache_common *armv8_cache)
  156. {
  157. int cl;
  158. if (armv8_cache->info == -1) {
  159. command_print(cmd, "cache not yet identified");
  160. return ERROR_OK;
  161. }
  162. for (cl = 0; cl < armv8_cache->loc; cl++) {
  163. struct armv8_arch_cache *arch = &(armv8_cache->arch[cl]);
  164. if (arch->ctype & 1) {
  165. command_print(cmd,
  166. "L%d I-Cache: linelen %" PRIu32
  167. ", associativity %" PRIu32
  168. ", nsets %" PRIu32
  169. ", cachesize %" PRIu32 " KBytes",
  170. cl+1,
  171. arch->i_size.linelen,
  172. arch->i_size.associativity,
  173. arch->i_size.nsets,
  174. arch->i_size.cachesize);
  175. }
  176. if (arch->ctype >= 2) {
  177. command_print(cmd,
  178. "L%d D-Cache: linelen %" PRIu32
  179. ", associativity %" PRIu32
  180. ", nsets %" PRIu32
  181. ", cachesize %" PRIu32 " KBytes",
  182. cl+1,
  183. arch->d_u_size.linelen,
  184. arch->d_u_size.associativity,
  185. arch->d_u_size.nsets,
  186. arch->d_u_size.cachesize);
  187. }
  188. }
  189. return ERROR_OK;
  190. }
  191. static int _armv8_flush_all_data(struct target *target)
  192. {
  193. return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target));
  194. }
  195. static int armv8_flush_all_data(struct target *target)
  196. {
  197. int retval = ERROR_FAIL;
  198. /* check that armv8_cache is correctly identify */
  199. struct armv8_common *armv8 = target_to_armv8(target);
  200. if (armv8->armv8_mmu.armv8_cache.info == -1) {
  201. LOG_ERROR("trying to flush un-identified cache");
  202. return retval;
  203. }
  204. if (target->smp) {
  205. /* look if all the other target have been flushed in order to flush level
  206. * 2 */
  207. struct target_list *head;
  208. struct target *curr;
  209. head = target->head;
  210. while (head != (struct target_list *)NULL) {
  211. curr = head->target;
  212. if (curr->state == TARGET_HALTED) {
  213. LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid);
  214. retval = _armv8_flush_all_data(curr);
  215. }
  216. head = head->next;
  217. }
  218. } else
  219. retval = _armv8_flush_all_data(target);
  220. return retval;
  221. }
  222. static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
  223. {
  224. struct armv8_common *armv8 = dpm->arm->arch_info;
  225. int retval = ERROR_OK;
  226. /* select cache level */
  227. retval = dpm->instr_write_data_r0(dpm,
  228. armv8_opcode(armv8, WRITE_REG_CSSELR),
  229. (cl << 1) | (ct == 1 ? 1 : 0));
  230. if (retval != ERROR_OK)
  231. goto done;
  232. retval = dpm->instr_read_data_r0(dpm,
  233. armv8_opcode(armv8, READ_REG_CCSIDR),
  234. cache_reg);
  235. done:
  236. return retval;
  237. }
  238. static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg)
  239. {
  240. struct armv8_cachesize size;
  241. int i = 0;
  242. size.linelen = 16 << (cache_reg & 0x7);
  243. size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
  244. size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
  245. size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
  246. /* compute info for set way operation on cache */
  247. size.index_shift = (cache_reg & 0x7) + 4;
  248. size.index = (cache_reg >> 13) & 0x7fff;
  249. size.way = ((cache_reg >> 3) & 0x3ff);
  250. while (((size.way << i) & 0x80000000) == 0)
  251. i++;
  252. size.way_shift = i;
  253. return size;
  254. }
  255. int armv8_identify_cache(struct armv8_common *armv8)
  256. {
  257. /* read cache descriptor */
  258. int retval = ERROR_FAIL;
  259. struct arm *arm = &armv8->arm;
  260. struct arm_dpm *dpm = armv8->arm.dpm;
  261. uint32_t csselr, clidr, ctr;
  262. uint32_t cache_reg;
  263. int cl, ctype;
  264. struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
  265. retval = dpm->prepare(dpm);
  266. if (retval != ERROR_OK)
  267. goto done;
  268. /* check if we're in an unprivileged mode */
  269. if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
  270. retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
  271. if (retval != ERROR_OK)
  272. return retval;
  273. }
  274. /* retrieve CTR */
  275. retval = dpm->instr_read_data_r0(dpm,
  276. armv8_opcode(armv8, READ_REG_CTR), &ctr);
  277. if (retval != ERROR_OK)
  278. goto done;
  279. cache->iminline = 4UL << (ctr & 0xf);
  280. cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
  281. LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32,
  282. ctr, cache->iminline, cache->dminline);
  283. /* retrieve CLIDR */
  284. retval = dpm->instr_read_data_r0(dpm,
  285. armv8_opcode(armv8, READ_REG_CLIDR), &clidr);
  286. if (retval != ERROR_OK)
  287. goto done;
  288. cache->loc = (clidr & 0x7000000) >> 24;
  289. LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc);
  290. /* retrieve selected cache for later restore
  291. * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
  292. retval = dpm->instr_read_data_r0(dpm,
  293. armv8_opcode(armv8, READ_REG_CSSELR), &csselr);
  294. if (retval != ERROR_OK)
  295. goto done;
  296. /* retrieve all available inner caches */
  297. for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
  298. /* isolate cache type at current level */
  299. ctype = clidr & 7;
  300. /* skip reserved values */
  301. if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE)
  302. continue;
  303. /* separate d or unified d/i cache at this level ? */
  304. if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) {
  305. /* retrieve d-cache info */
  306. retval = get_cache_info(dpm, cl, 0, &cache_reg);
  307. if (retval != ERROR_OK)
  308. goto done;
  309. cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
  310. LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
  311. cache->arch[cl].d_u_size.index,
  312. cache->arch[cl].d_u_size.index_shift,
  313. cache->arch[cl].d_u_size.way,
  314. cache->arch[cl].d_u_size.way_shift);
  315. LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
  316. cache->arch[cl].d_u_size.linelen,
  317. cache->arch[cl].d_u_size.cachesize,
  318. cache->arch[cl].d_u_size.associativity);
  319. }
  320. /* separate i-cache at this level ? */
  321. if (ctype & CACHE_LEVEL_HAS_I_CACHE) {
  322. /* retrieve i-cache info */
  323. retval = get_cache_info(dpm, cl, 1, &cache_reg);
  324. if (retval != ERROR_OK)
  325. goto done;
  326. cache->arch[cl].i_size = decode_cache_reg(cache_reg);
  327. LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
  328. cache->arch[cl].i_size.index,
  329. cache->arch[cl].i_size.index_shift,
  330. cache->arch[cl].i_size.way,
  331. cache->arch[cl].i_size.way_shift);
  332. LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
  333. cache->arch[cl].i_size.linelen,
  334. cache->arch[cl].i_size.cachesize,
  335. cache->arch[cl].i_size.associativity);
  336. }
  337. cache->arch[cl].ctype = ctype;
  338. }
  339. /* restore selected cache */
  340. dpm->instr_write_data_r0(dpm,
  341. armv8_opcode(armv8, WRITE_REG_CSSELR), csselr);
  342. if (retval != ERROR_OK)
  343. goto done;
  344. armv8->armv8_mmu.armv8_cache.info = 1;
  345. /* if no l2 cache initialize l1 data cache flush function function */
  346. if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) {
  347. armv8->armv8_mmu.armv8_cache.display_cache_info =
  348. armv8_handle_inner_cache_info_command;
  349. armv8->armv8_mmu.armv8_cache.flush_all_data_cache =
  350. armv8_flush_all_data;
  351. }
  352. done:
  353. armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
  354. dpm->finish(dpm);
  355. return retval;
  356. }