flipper_application.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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_compatible(
  37. &app->manifest, elf_file_get_api_interface(app->elf))) {
  38. return FlipperApplicationPreloadStatusApiMismatch;
  39. }
  40. return FlipperApplicationPreloadStatusSuccess;
  41. }
  42. /* Parse headers, load manifest */
  43. FlipperApplicationPreloadStatus
  44. flipper_application_preload_manifest(FlipperApplication* app, const char* path) {
  45. if(!elf_file_open(app->elf, path) || !elf_file_load_manifest(app->elf, &app->manifest)) {
  46. return FlipperApplicationPreloadStatusInvalidFile;
  47. }
  48. return flipper_application_validate_manifest(app);
  49. }
  50. /* Parse headers, load full file */
  51. FlipperApplicationPreloadStatus
  52. flipper_application_preload(FlipperApplication* app, const char* path) {
  53. if(!elf_file_open(app->elf, path) || !elf_file_load_section_table(app->elf, &app->manifest)) {
  54. return FlipperApplicationPreloadStatusInvalidFile;
  55. }
  56. return flipper_application_validate_manifest(app);
  57. }
  58. const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) {
  59. return &app->manifest;
  60. }
  61. FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) {
  62. last_loaded_app = app;
  63. ELFFileLoadStatus status = elf_file_load_sections(app->elf);
  64. switch(status) {
  65. case ELFFileLoadStatusSuccess:
  66. elf_file_init_debug_info(app->elf, &app->state);
  67. return FlipperApplicationLoadStatusSuccess;
  68. case ELFFileLoadStatusNoFreeMemory:
  69. return FlipperApplicationLoadStatusNoFreeMemory;
  70. case ELFFileLoadStatusMissingImports:
  71. return FlipperApplicationLoadStatusMissingImports;
  72. default:
  73. return FlipperApplicationLoadStatusUnspecifiedError;
  74. }
  75. }
  76. static int32_t flipper_application_thread(void* context) {
  77. elf_file_pre_run(last_loaded_app->elf);
  78. int32_t result = elf_file_run(last_loaded_app->elf, context);
  79. elf_file_post_run(last_loaded_app->elf);
  80. // wait until all notifications from RAM are completed
  81. NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
  82. const NotificationSequence sequence_empty = {
  83. NULL,
  84. };
  85. notification_message_block(notifications, &sequence_empty);
  86. furi_record_close(RECORD_NOTIFICATION);
  87. return result;
  88. }
  89. FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) {
  90. furi_check(app->thread == NULL);
  91. const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app);
  92. furi_check(manifest->stack_size > 0);
  93. app->thread = furi_thread_alloc_ex(
  94. manifest->name, manifest->stack_size, flipper_application_thread, args);
  95. return app->thread;
  96. }
  97. static const char* preload_status_strings[] = {
  98. [FlipperApplicationPreloadStatusSuccess] = "Success",
  99. [FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
  100. [FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
  101. [FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
  102. [FlipperApplicationPreloadStatusApiMismatch] = "API version mismatch",
  103. [FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
  104. };
  105. static const char* load_status_strings[] = {
  106. [FlipperApplicationLoadStatusSuccess] = "Success",
  107. [FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
  108. [FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
  109. [FlipperApplicationLoadStatusMissingImports] = "Found unsatisfied imports",
  110. };
  111. const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
  112. if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) {
  113. return "Unknown error";
  114. }
  115. return preload_status_strings[status];
  116. }
  117. const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
  118. if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) {
  119. return "Unknown error";
  120. }
  121. return load_status_strings[status];
  122. }