profiler.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Copyright (c) 2017, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /*******************************************************************************
  7. * The profiler stores the timestamps captured during cold boot to the shared
  8. * memory for the non-secure world. The non-secure world driver parses the
  9. * shared memory block and writes the contents to a file on the device, which
  10. * can be later extracted for analysis.
  11. *
  12. * Profiler memory map
  13. *
  14. * TOP --------------------------- ---
  15. * Trusted OS timestamps 3KB
  16. * --------------------------- ---
  17. * Trusted Firmware timestamps 1KB
  18. * BASE --------------------------- ---
  19. *
  20. ******************************************************************************/
  21. #include <arch.h>
  22. #include <arch_helpers.h>
  23. #include <assert.h>
  24. #include <lib/mmio.h>
  25. #include <lib/utils_def.h>
  26. #include <lib/xlat_tables/xlat_tables_v2.h>
  27. #include <profiler.h>
  28. #include <stdbool.h>
  29. #include <string.h>
  30. static uint64_t shmem_base_addr;
  31. #define MAX_PROFILER_RECORDS U(16)
  32. #define TAG_LEN_BYTES U(56)
  33. /*******************************************************************************
  34. * Profiler entry format
  35. ******************************************************************************/
  36. typedef struct {
  37. /* text explaining the timestamp location in code */
  38. uint8_t tag[TAG_LEN_BYTES];
  39. /* timestamp value */
  40. uint64_t timestamp;
  41. } profiler_rec_t;
  42. static profiler_rec_t *head, *cur, *tail;
  43. static uint32_t tmr;
  44. static bool is_shmem_buf_mapped;
  45. /*******************************************************************************
  46. * Initialise the profiling library
  47. ******************************************************************************/
  48. void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
  49. {
  50. uint64_t shmem_end_base;
  51. assert(shmem_base != ULL(0));
  52. assert(tmr_base != U(0));
  53. /* store the buffer address */
  54. shmem_base_addr = shmem_base;
  55. /* calculate the base address of the last record */
  56. shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
  57. (MAX_PROFILER_RECORDS - U(1)));
  58. /* calculate the head, tail and cur values */
  59. head = (profiler_rec_t *)shmem_base;
  60. tail = (profiler_rec_t *)shmem_end_base;
  61. cur = head;
  62. /* timer used to get the current timestamp */
  63. tmr = tmr_base;
  64. }
  65. /*******************************************************************************
  66. * Add tag and timestamp to profiler
  67. ******************************************************************************/
  68. void boot_profiler_add_record(const char *str)
  69. {
  70. unsigned int len;
  71. /* calculate the length of the tag */
  72. if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
  73. len = TAG_LEN_BYTES;
  74. } else {
  75. len = (unsigned int)strlen(str) + U(1);
  76. }
  77. if (head != NULL) {
  78. /*
  79. * The profiler runs with/without MMU enabled. Check
  80. * if MMU is enabled and memmap the shmem buffer, in
  81. * case it is.
  82. */
  83. if ((!is_shmem_buf_mapped) &&
  84. ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
  85. (void)mmap_add_dynamic_region(shmem_base_addr,
  86. shmem_base_addr,
  87. PROFILER_SIZE_BYTES,
  88. (MT_NS | MT_RW | MT_EXECUTE_NEVER));
  89. is_shmem_buf_mapped = true;
  90. }
  91. /* write the tag and timestamp to buffer */
  92. (void)snprintf((char *)cur->tag, len, "%s", str);
  93. cur->timestamp = mmio_read_32(tmr);
  94. /* start from head if we reached the end */
  95. if (cur == tail) {
  96. cur = head;
  97. } else {
  98. cur++;
  99. }
  100. }
  101. }
  102. /*******************************************************************************
  103. * Deinint the profiler
  104. ******************************************************************************/
  105. void boot_profiler_deinit(void)
  106. {
  107. if (shmem_base_addr != ULL(0)) {
  108. /* clean up resources */
  109. cur = NULL;
  110. head = NULL;
  111. tail = NULL;
  112. /* flush the shmem for it to be visible to the NS world */
  113. flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
  114. /* unmap the shmem buffer */
  115. if (is_shmem_buf_mapped) {
  116. (void)mmap_remove_dynamic_region(shmem_base_addr,
  117. PROFILER_SIZE_BYTES);
  118. }
  119. }
  120. }