flipper_application.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include "flipper_application.h"
  2. #include "elf/elf_file.h"
  3. #include <notification/notification_messages.h>
  4. #define TAG "fapp"
  5. struct FlipperApplication {
  6. ELFDebugInfo state;
  7. FlipperApplicationManifest manifest;
  8. ELFFile* elf;
  9. FuriThread* thread;
  10. };
  11. /* For debugger access to app state */
  12. FlipperApplication* last_loaded_app = NULL;
  13. FlipperApplication*
  14. flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) {
  15. FlipperApplication* app = malloc(sizeof(FlipperApplication));
  16. app->elf = elf_file_alloc(storage, api_interface);
  17. app->thread = NULL;
  18. return app;
  19. }
  20. void flipper_application_free(FlipperApplication* app) {
  21. furi_assert(app);
  22. if(app->thread) {
  23. furi_thread_join(app->thread);
  24. furi_thread_free(app->thread);
  25. }
  26. last_loaded_app = NULL;
  27. elf_file_clear_debug_info(&app->state);
  28. elf_file_free(app->elf);
  29. free(app);
  30. }
  31. static FlipperApplicationPreloadStatus
  32. flipper_application_validate_manifest(FlipperApplication* app) {
  33. if(!flipper_application_manifest_is_valid(&app->manifest)) {
  34. return FlipperApplicationPreloadStatusInvalidManifest;
  35. }
  36. if(!flipper_application_manifest_is_target_compatible(&app->manifest)) {
  37. return FlipperApplicationPreloadStatusTargetMismatch;
  38. }
  39. if(!flipper_application_manifest_is_compatible(
  40. &app->manifest, elf_file_get_api_interface(app->elf))) {
  41. return FlipperApplicationPreloadStatusApiMismatch;
  42. }
  43. return FlipperApplicationPreloadStatusSuccess;
  44. }
  45. /* Parse headers, load manifest */
  46. FlipperApplicationPreloadStatus
  47. flipper_application_preload_manifest(FlipperApplication* app, const char* path) {
  48. if(!elf_file_open(app->elf, path) || !elf_file_load_manifest(app->elf, &app->manifest)) {
  49. return FlipperApplicationPreloadStatusInvalidFile;
  50. }
  51. return flipper_application_validate_manifest(app);
  52. }
  53. /* Parse headers, load full file */
  54. FlipperApplicationPreloadStatus
  55. flipper_application_preload(FlipperApplication* app, const char* path) {
  56. if(!elf_file_open(app->elf, path) || !elf_file_load_section_table(app->elf, &app->manifest)) {
  57. return FlipperApplicationPreloadStatusInvalidFile;
  58. }
  59. return flipper_application_validate_manifest(app);
  60. }
  61. const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) {
  62. return &app->manifest;
  63. }
  64. FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) {
  65. last_loaded_app = app;
  66. ELFFileLoadStatus status = elf_file_load_sections(app->elf);
  67. switch(status) {
  68. case ELFFileLoadStatusSuccess:
  69. elf_file_init_debug_info(app->elf, &app->state);
  70. return FlipperApplicationLoadStatusSuccess;
  71. case ELFFileLoadStatusNoFreeMemory:
  72. return FlipperApplicationLoadStatusNoFreeMemory;
  73. case ELFFileLoadStatusMissingImports:
  74. return FlipperApplicationLoadStatusMissingImports;
  75. default:
  76. return FlipperApplicationLoadStatusUnspecifiedError;
  77. }
  78. }
  79. static int32_t flipper_application_thread(void* context) {
  80. elf_file_pre_run(last_loaded_app->elf);
  81. int32_t result = elf_file_run(last_loaded_app->elf, context);
  82. elf_file_post_run(last_loaded_app->elf);
  83. // wait until all notifications from RAM are completed
  84. NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
  85. const NotificationSequence sequence_empty = {
  86. NULL,
  87. };
  88. notification_message_block(notifications, &sequence_empty);
  89. furi_record_close(RECORD_NOTIFICATION);
  90. return result;
  91. }
  92. FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) {
  93. furi_check(app->thread == NULL);
  94. const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app);
  95. furi_check(manifest->stack_size > 0);
  96. app->thread = furi_thread_alloc_ex(
  97. manifest->name, manifest->stack_size, flipper_application_thread, args);
  98. return app->thread;
  99. }
  100. static const char* preload_status_strings[] = {
  101. [FlipperApplicationPreloadStatusSuccess] = "Success",
  102. [FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
  103. [FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
  104. [FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
  105. [FlipperApplicationPreloadStatusApiMismatch] = "API version mismatch",
  106. [FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
  107. };
  108. static const char* load_status_strings[] = {
  109. [FlipperApplicationLoadStatusSuccess] = "Success",
  110. [FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
  111. [FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
  112. [FlipperApplicationLoadStatusMissingImports] = "Found unsatisfied imports",
  113. };
  114. const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
  115. if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) {
  116. return "Unknown error";
  117. }
  118. return preload_status_strings[status];
  119. }
  120. const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
  121. if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) {
  122. return "Unknown error";
  123. }
  124. return load_status_strings[status];
  125. }