mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge remote-tracking branch 'OFW/dev' into dev [ci skip]
This commit is contained in:
@@ -192,7 +192,7 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
|
|||||||
} else if(
|
} else if(
|
||||||
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
|
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
|
||||||
data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 ||
|
data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 ||
|
||||||
data->type == MfUltralightTypeUL21) {
|
data->type == MfUltralightTypeUL21 || data->type == MfUltralightTypeOrigin) {
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Write",
|
"Write",
|
||||||
|
|||||||
@@ -464,13 +464,10 @@ static bool nfc_is_hal_ready(void) {
|
|||||||
// No connection to the chip, show an error screen
|
// No connection to the chip, show an error screen
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
dialog_message_set_header(message, "Error: NFC Chip Failed", 64, 0, AlignCenter, AlignTop);
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
message,
|
message, "Send error photo via\nsupport.flipper.net", 0, 63, AlignLeft, AlignBottom);
|
||||||
"Error!\nNFC chip failed to start\n\n\nSend a photo of this to:\nsupport@flipperzero.one",
|
//dialog_message_set_icon(message, &I_err_09, 128 - 25, 64 - 25);
|
||||||
0,
|
|
||||||
0,
|
|
||||||
AlignLeft,
|
|
||||||
AlignTop);
|
|
||||||
dialog_message_show(dialogs, message);
|
dialog_message_show(dialogs, message);
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ static const char* loader_find_external_application_by_name(const char* app_name
|
|||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
LoaderStatus
|
static LoaderMessageLoaderStatusResult loader_start_internal(
|
||||||
loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) {
|
Loader* loader,
|
||||||
furi_check(loader);
|
const char* name,
|
||||||
furi_check(name);
|
const char* args,
|
||||||
|
FuriString* error_message) {
|
||||||
LoaderMessage message;
|
LoaderMessage message;
|
||||||
LoaderMessageLoaderStatusResult result;
|
LoaderMessageLoaderStatusResult result;
|
||||||
|
|
||||||
@@ -44,31 +44,102 @@ LoaderStatus
|
|||||||
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
|
||||||
api_lock_wait_unlock_and_free(message.api_lock);
|
api_lock_wait_unlock_and_free(message.api_lock);
|
||||||
|
|
||||||
return result.value;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
typedef struct {
|
||||||
loader_show_gui_error(LoaderStatus status, const char* name, FuriString* error_message) {
|
const char* error;
|
||||||
if(status == LoaderStatusErrorUnknownApp &&
|
const char* description;
|
||||||
loader_find_external_application_by_name(name) != NULL) {
|
const char* url;
|
||||||
// Special case for external apps
|
const Icon* icon;
|
||||||
|
} LoaderError;
|
||||||
|
|
||||||
|
static const LoaderError err_app_not_found =
|
||||||
|
{"App Not Found", "Update firmware or app", "err_01", &I_err_01};
|
||||||
|
static const LoaderError err_invalid_flie = {"Invalid File", "Update the app", "err_02", &I_err_02};
|
||||||
|
static const LoaderError err_invalid_manifest =
|
||||||
|
{"Invalid Manifest", "Update firmware or app", "err_03", &I_err_03};
|
||||||
|
static const LoaderError err_missing_imports =
|
||||||
|
{"Missing Imports", "Update firmware or app", "err_04", &I_err_04};
|
||||||
|
static const LoaderError err_hw_target_mismatch =
|
||||||
|
{"HW Target\nMismatch", "App not supported", "err_05", &I_err_05};
|
||||||
|
/*static const LoaderError err_outdated_app = {"Outdated App", "Update the app", "err_06", &I_err_06};
|
||||||
|
static const LoaderError err_outdated_firmware =
|
||||||
|
{"Outdated\nFirmware", "Update firmware", "err_07", &I_err_07};*/
|
||||||
|
|
||||||
|
static void loader_dialog_prepare_and_show(DialogsApp* dialogs, const LoaderError* err) {
|
||||||
|
FuriString* header = furi_string_alloc_printf("Error: %s", err->error);
|
||||||
|
FuriString* text =
|
||||||
|
furi_string_alloc_printf("%s\nLearn more:\nr.flipper.net/%s", err->description, err->url);
|
||||||
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
|
||||||
|
dialog_message_set_header(message, furi_string_get_cstr(header), 64, 0, AlignCenter, AlignTop);
|
||||||
|
dialog_message_set_text(message, furi_string_get_cstr(text), 0, 63, AlignLeft, AlignBottom);
|
||||||
|
dialog_message_set_icon(message, err->icon, 128 - 25, 64 - 25);
|
||||||
|
dialog_message_show(dialogs, message);
|
||||||
|
|
||||||
|
dialog_message_free(message);
|
||||||
|
furi_string_free(header);
|
||||||
|
furi_string_free(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loader_show_gui_error(
|
||||||
|
LoaderMessageLoaderStatusResult status,
|
||||||
|
const char* name,
|
||||||
|
FuriString* error_message) {
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
|
||||||
|
if(status.value == LoaderStatusErrorUnknownApp &&
|
||||||
|
loader_find_external_application_by_name(name) != NULL) {
|
||||||
|
// Special case for external apps
|
||||||
dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop);
|
dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop);
|
||||||
dialog_message_set_buttons(message, NULL, NULL, NULL);
|
|
||||||
dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22);
|
dialog_message_set_icon(message, &I_WarningDolphinFlip_45x42, 83, 22);
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop);
|
message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop);
|
||||||
dialog_message_show(dialogs, message);
|
dialog_message_show(dialogs, message);
|
||||||
dialog_message_free(message);
|
} else if(status.value == LoaderStatusErrorUnknownApp) {
|
||||||
furi_record_close(RECORD_DIALOGS);
|
loader_dialog_prepare_and_show(dialogs, &err_app_not_found);
|
||||||
} else if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) {
|
} else if(status.value == LoaderStatusErrorInternal) {
|
||||||
// TODO FL-3522: we have many places where we can emit a double start, ex: desktop, menu
|
// TODO FL-3522: we have many places where we can emit a double start, ex: desktop, menu
|
||||||
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
|
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
switch(status.error) {
|
||||||
DialogMessage* message = dialog_message_alloc();
|
case LoaderStatusErrorInvalidFile:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_invalid_flie);
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorInvalidManifest:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_invalid_manifest);
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorMissingImports:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_missing_imports);
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorHWMismatch:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_hw_target_mismatch);
|
||||||
|
break;
|
||||||
|
/*case LoaderStatusErrorOutdatedApp:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_outdated_app);
|
||||||
|
break;
|
||||||
|
case LoaderStatusErrorOutdatedFirmware:
|
||||||
|
loader_dialog_prepare_and_show(dialogs, &err_outdated_firmware);
|
||||||
|
break;*/
|
||||||
|
case LoaderStatusErrorOutOfMemory:
|
||||||
|
dialog_message_set_header(
|
||||||
|
message, "Error: Out of Memory", 64, 0, AlignCenter, AlignTop);
|
||||||
|
dialog_message_set_text(
|
||||||
|
message,
|
||||||
|
"Not enough RAM to run the\napp. Please reboot the device",
|
||||||
|
64,
|
||||||
|
13,
|
||||||
|
AlignCenter,
|
||||||
|
AlignTop);
|
||||||
|
dialog_message_set_buttons(message, NULL, NULL, "Reboot");
|
||||||
|
if(dialog_message_show(dialogs, message) == DialogMessageButtonRight) {
|
||||||
|
furi_hal_power_reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Generic error
|
||||||
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
|
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
|
||||||
dialog_message_set_buttons(message, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
furi_string_replace(error_message, ":", "\n");
|
furi_string_replace(error_message, ":", "\n");
|
||||||
furi_string_replace(error_message, "/ext/apps/", "");
|
furi_string_replace(error_message, "/ext/apps/", "");
|
||||||
@@ -77,11 +148,23 @@ static void
|
|||||||
|
|
||||||
dialog_message_set_text(
|
dialog_message_set_text(
|
||||||
message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter);
|
message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter);
|
||||||
|
|
||||||
dialog_message_show(dialogs, message);
|
dialog_message_show(dialogs, message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoaderStatus
|
||||||
|
loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) {
|
||||||
|
furi_check(loader);
|
||||||
|
furi_check(name);
|
||||||
|
|
||||||
|
LoaderMessageLoaderStatusResult result =
|
||||||
|
loader_start_internal(loader, name, args, error_message);
|
||||||
|
return result.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) {
|
LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) {
|
||||||
@@ -89,10 +172,11 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
|
|||||||
furi_check(name);
|
furi_check(name);
|
||||||
|
|
||||||
FuriString* error_message = furi_string_alloc();
|
FuriString* error_message = furi_string_alloc();
|
||||||
LoaderStatus status = loader_start(loader, name, args, error_message);
|
LoaderMessageLoaderStatusResult result =
|
||||||
loader_show_gui_error(status, name, error_message);
|
loader_start_internal(loader, name, args, error_message);
|
||||||
|
loader_show_gui_error(result, name, error_message);
|
||||||
furi_string_free(error_message);
|
furi_string_free(error_message);
|
||||||
return status;
|
return result.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args) {
|
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args) {
|
||||||
@@ -318,14 +402,47 @@ static LoaderStatus loader_make_success_status(FuriString* error_message) {
|
|||||||
return LoaderStatusOk;
|
return LoaderStatusOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LoaderStatus loader_start_external_app(
|
static LoaderStatusError
|
||||||
|
loader_status_error_from_preload_status(FlipperApplicationPreloadStatus status) {
|
||||||
|
switch(status) {
|
||||||
|
case FlipperApplicationPreloadStatusInvalidFile:
|
||||||
|
return LoaderStatusErrorInvalidFile;
|
||||||
|
case FlipperApplicationPreloadStatusNotEnoughMemory:
|
||||||
|
return LoaderStatusErrorOutOfMemory;
|
||||||
|
case FlipperApplicationPreloadStatusInvalidManifest:
|
||||||
|
return LoaderStatusErrorInvalidManifest;
|
||||||
|
case FlipperApplicationPreloadStatusApiTooOld:
|
||||||
|
return LoaderStatusErrorOutdatedApp;
|
||||||
|
case FlipperApplicationPreloadStatusApiTooNew:
|
||||||
|
return LoaderStatusErrorOutdatedFirmware;
|
||||||
|
case FlipperApplicationPreloadStatusTargetMismatch:
|
||||||
|
return LoaderStatusErrorHWMismatch;
|
||||||
|
default:
|
||||||
|
return LoaderStatusErrorUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LoaderStatusError
|
||||||
|
loader_status_error_from_load_status(FlipperApplicationLoadStatus status) {
|
||||||
|
switch(status) {
|
||||||
|
case FlipperApplicationLoadStatusMissingImports:
|
||||||
|
return LoaderStatusErrorMissingImports;
|
||||||
|
default:
|
||||||
|
return LoaderStatusErrorUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LoaderMessageLoaderStatusResult loader_start_external_app(
|
||||||
Loader* loader,
|
Loader* loader,
|
||||||
Storage* storage,
|
Storage* storage,
|
||||||
const char* path,
|
const char* path,
|
||||||
const char* args,
|
const char* args,
|
||||||
FuriString* error_message,
|
FuriString* error_message,
|
||||||
bool ignore_mismatch) {
|
bool ignore_api_mismatch) {
|
||||||
LoaderStatus status = loader_make_success_status(error_message);
|
LoaderMessageLoaderStatusResult result;
|
||||||
|
result.value = loader_make_success_status(error_message);
|
||||||
|
result.error = LoaderStatusErrorUnknown;
|
||||||
|
|
||||||
LoaderEvent event;
|
LoaderEvent event;
|
||||||
event.type = LoaderEventTypeApplicationBeforeLoad;
|
event.type = LoaderEventTypeApplicationBeforeLoad;
|
||||||
furi_pubsub_publish(loader->pubsub, &event);
|
furi_pubsub_publish(loader->pubsub, &event);
|
||||||
@@ -341,7 +458,7 @@ static LoaderStatus loader_start_external_app(
|
|||||||
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
|
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
|
||||||
if((preload_res == FlipperApplicationPreloadStatusApiTooOld) ||
|
if((preload_res == FlipperApplicationPreloadStatusApiTooOld) ||
|
||||||
(preload_res == FlipperApplicationPreloadStatusApiTooNew)) {
|
(preload_res == FlipperApplicationPreloadStatusApiTooNew)) {
|
||||||
if(!ignore_mismatch) {
|
if(!ignore_api_mismatch) {
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
DialogMessage* message = dialog_message_alloc();
|
DialogMessage* message = dialog_message_alloc();
|
||||||
dialog_message_set_header(
|
dialog_message_set_header(
|
||||||
@@ -355,11 +472,13 @@ static LoaderStatus loader_start_external_app(
|
|||||||
AlignCenter,
|
AlignCenter,
|
||||||
AlignCenter);
|
AlignCenter);
|
||||||
if(dialog_message_show(dialogs, message) == DialogMessageButtonRight) {
|
if(dialog_message_show(dialogs, message) == DialogMessageButtonRight) {
|
||||||
status = loader_make_status_error(
|
result.value = loader_make_status_error(
|
||||||
LoaderStatusErrorApiMismatch, error_message, "API Mismatch");
|
LoaderStatusErrorApiMismatch, error_message, "API Mismatch");
|
||||||
|
result.error = loader_status_error_from_preload_status(preload_res);
|
||||||
} else {
|
} else {
|
||||||
status = loader_make_status_error(
|
result.value = loader_make_status_error(
|
||||||
LoaderStatusErrorApiMismatchExit, error_message, "API Mismatch");
|
LoaderStatusErrorApiMismatchExit, error_message, "API Mismatch");
|
||||||
|
result.error = loader_status_error_from_preload_status(preload_res);
|
||||||
}
|
}
|
||||||
dialog_message_free(message);
|
dialog_message_free(message);
|
||||||
furi_record_close(RECORD_DIALOGS);
|
furi_record_close(RECORD_DIALOGS);
|
||||||
@@ -367,12 +486,13 @@ static LoaderStatus loader_start_external_app(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char* err_msg = flipper_application_preload_status_to_string(preload_res);
|
const char* err_msg = flipper_application_preload_status_to_string(preload_res);
|
||||||
status = loader_make_status_error(
|
result.value = loader_make_status_error(
|
||||||
LoaderStatusErrorInternal,
|
LoaderStatusErrorInternal,
|
||||||
error_message,
|
error_message,
|
||||||
"Preload failed %s: %s",
|
"Preload failed, %s: %s",
|
||||||
path,
|
path,
|
||||||
err_msg);
|
err_msg);
|
||||||
|
result.error = loader_status_error_from_preload_status(preload_res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,15 +501,16 @@ static LoaderStatus loader_start_external_app(
|
|||||||
flipper_application_map_to_memory(loader->app.fap);
|
flipper_application_map_to_memory(loader->app.fap);
|
||||||
if(load_status != FlipperApplicationLoadStatusSuccess) {
|
if(load_status != FlipperApplicationLoadStatusSuccess) {
|
||||||
const char* err_msg = flipper_application_load_status_to_string(load_status);
|
const char* err_msg = flipper_application_load_status_to_string(load_status);
|
||||||
status = loader_make_status_error(
|
result.value = loader_make_status_error(
|
||||||
LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg);
|
LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg);
|
||||||
|
result.error = loader_status_error_from_load_status(load_status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start));
|
FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start));
|
||||||
|
|
||||||
if(flipper_application_is_plugin(loader->app.fap)) {
|
if(flipper_application_is_plugin(loader->app.fap)) {
|
||||||
status = loader_make_status_error(
|
result.value = loader_make_status_error(
|
||||||
LoaderStatusErrorInternal, error_message, "Plugin %s is not runnable", path);
|
LoaderStatusErrorInternal, error_message, "Plugin %s is not runnable", path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -411,14 +532,14 @@ static LoaderStatus loader_start_external_app(
|
|||||||
loader_start_app_thread(loader, FlipperInternalApplicationFlagDefault);
|
loader_start_app_thread(loader, FlipperInternalApplicationFlagDefault);
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
if(status != LoaderStatusOk) {
|
if(result.value != LoaderStatusOk) {
|
||||||
flipper_application_free(loader->app.fap);
|
flipper_application_free(loader->app.fap);
|
||||||
loader->app.fap = NULL;
|
loader->app.fap = NULL;
|
||||||
event.type = LoaderEventTypeApplicationLoadFailed;
|
event.type = LoaderEventTypeApplicationLoadFailed;
|
||||||
furi_pubsub_publish(loader->pubsub, &event);
|
furi_pubsub_publish(loader->pubsub, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// process messages
|
// process messages
|
||||||
@@ -454,23 +575,26 @@ static bool loader_do_is_locked(Loader* loader) {
|
|||||||
return loader->app.thread != NULL;
|
return loader->app.thread != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LoaderStatus loader_do_start_by_name(
|
static LoaderMessageLoaderStatusResult loader_do_start_by_name(
|
||||||
Loader* loader,
|
Loader* loader,
|
||||||
const char* name,
|
const char* name,
|
||||||
const char* args,
|
const char* args,
|
||||||
FuriString* error_message) {
|
FuriString* error_message) {
|
||||||
LoaderStatus status;
|
LoaderMessageLoaderStatusResult status;
|
||||||
|
status.value = loader_make_success_status(error_message);
|
||||||
|
status.error = LoaderStatusErrorUnknown;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// check lock
|
// check lock
|
||||||
if(loader_do_is_locked(loader)) {
|
if(loader_do_is_locked(loader)) {
|
||||||
if(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE) {
|
if(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE) {
|
||||||
status = loader_make_status_error(
|
status.value = loader_make_status_error(
|
||||||
LoaderStatusErrorAppStarted, error_message, "Loader is locked");
|
LoaderStatusErrorAppStarted, error_message, "Loader is locked");
|
||||||
} else {
|
} else {
|
||||||
const char* current_thread_name =
|
const char* current_thread_name =
|
||||||
furi_thread_get_name(furi_thread_get_id(loader->app.thread));
|
furi_thread_get_name(furi_thread_get_id(loader->app.thread));
|
||||||
|
|
||||||
status = loader_make_status_error(
|
status.value = loader_make_status_error(
|
||||||
LoaderStatusErrorAppStarted,
|
LoaderStatusErrorAppStarted,
|
||||||
error_message,
|
error_message,
|
||||||
"Loader is locked, please close the \"%s\" first",
|
"Loader is locked, please close the \"%s\" first",
|
||||||
@@ -484,7 +608,7 @@ static LoaderStatus loader_do_start_by_name(
|
|||||||
const FlipperInternalApplication* app = loader_find_application_by_name(name);
|
const FlipperInternalApplication* app = loader_find_application_by_name(name);
|
||||||
if(app) {
|
if(app) {
|
||||||
loader_start_internal_app(loader, app, args);
|
loader_start_internal_app(loader, app, args);
|
||||||
status = loader_make_success_status(error_message);
|
status.value = loader_make_success_status(error_message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,7 +616,7 @@ static LoaderStatus loader_do_start_by_name(
|
|||||||
// check Applications
|
// check Applications
|
||||||
if(strcmp(name, LOADER_APPLICATIONS_NAME) == 0) {
|
if(strcmp(name, LOADER_APPLICATIONS_NAME) == 0) {
|
||||||
loader_do_applications_show(loader);
|
loader_do_applications_show(loader);
|
||||||
status = loader_make_success_status(error_message);
|
status.value = loader_make_success_status(error_message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +634,7 @@ static LoaderStatus loader_do_start_by_name(
|
|||||||
if(storage_file_exists(storage, name)) {
|
if(storage_file_exists(storage, name)) {
|
||||||
status =
|
status =
|
||||||
loader_start_external_app(loader, storage, name, args, error_message, false);
|
loader_start_external_app(loader, storage, name, args, error_message, false);
|
||||||
if(status == LoaderStatusErrorApiMismatch) {
|
if(status.value == LoaderStatusErrorApiMismatch) {
|
||||||
status = loader_start_external_app(
|
status = loader_start_external_app(
|
||||||
loader, storage, name, args, error_message, true);
|
loader, storage, name, args, error_message, true);
|
||||||
}
|
}
|
||||||
@@ -520,7 +644,7 @@ static LoaderStatus loader_do_start_by_name(
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = loader_make_status_error(
|
status.value = loader_make_status_error(
|
||||||
LoaderStatusErrorUnknownApp, error_message, "Application \"%s\" not found", name);
|
LoaderStatusErrorUnknownApp, error_message, "Application \"%s\" not found", name);
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
@@ -595,13 +719,13 @@ int32_t loader_srv(void* p) {
|
|||||||
if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) {
|
if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) {
|
||||||
switch(message.type) {
|
switch(message.type) {
|
||||||
case LoaderMessageTypeStartByName:
|
case LoaderMessageTypeStartByName:
|
||||||
message.status_value->value = loader_do_start_by_name(
|
*(message.status_value) = loader_do_start_by_name(
|
||||||
loader, message.start.name, message.start.args, message.start.error_message);
|
loader, message.start.name, message.start.args, message.start.error_message);
|
||||||
api_lock_unlock(message.api_lock);
|
api_lock_unlock(message.api_lock);
|
||||||
break;
|
break;
|
||||||
case LoaderMessageTypeStartByNameDetachedWithGuiError: {
|
case LoaderMessageTypeStartByNameDetachedWithGuiError: {
|
||||||
FuriString* error_message = furi_string_alloc();
|
FuriString* error_message = furi_string_alloc();
|
||||||
LoaderStatus status = loader_do_start_by_name(
|
LoaderMessageLoaderStatusResult status = loader_do_start_by_name(
|
||||||
loader, message.start.name, message.start.args, error_message);
|
loader, message.start.name, message.start.args, error_message);
|
||||||
loader_show_gui_error(status, message.start.name, error_message);
|
loader_show_gui_error(status, message.start.name, error_message);
|
||||||
if(message.start.name) free((void*)message.start.name);
|
if(message.start.name) free((void*)message.start.name);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
|
|||||||
/**
|
/**
|
||||||
* @brief Start application detached with GUI error message
|
* @brief Start application detached with GUI error message
|
||||||
* @param[in] instance loader instance
|
* @param[in] instance loader instance
|
||||||
* @param[in] name application name
|
* @param[in] name application name or id
|
||||||
* @param[in] args application arguments
|
* @param[in] args application arguments
|
||||||
*/
|
*/
|
||||||
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args);
|
void loader_start_detached_with_gui_error(Loader* loader, const char* name, const char* args);
|
||||||
|
|||||||
@@ -39,8 +39,20 @@ typedef struct {
|
|||||||
FuriString* error_message;
|
FuriString* error_message;
|
||||||
} LoaderMessageStartByName;
|
} LoaderMessageStartByName;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LoaderStatusErrorUnknown,
|
||||||
|
LoaderStatusErrorInvalidFile,
|
||||||
|
LoaderStatusErrorInvalidManifest,
|
||||||
|
LoaderStatusErrorMissingImports,
|
||||||
|
LoaderStatusErrorHWMismatch,
|
||||||
|
LoaderStatusErrorOutdatedApp,
|
||||||
|
LoaderStatusErrorOutOfMemory,
|
||||||
|
LoaderStatusErrorOutdatedFirmware,
|
||||||
|
} LoaderStatusError;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LoaderStatus value;
|
LoaderStatus value;
|
||||||
|
LoaderStatusError error;
|
||||||
} LoaderMessageLoaderStatusResult;
|
} LoaderMessageLoaderStatusResult;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
BIN
assets/icons/Loader/err_01.png
Normal file
BIN
assets/icons/Loader/err_01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 394 B |
BIN
assets/icons/Loader/err_02.png
Normal file
BIN
assets/icons/Loader/err_02.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 397 B |
BIN
assets/icons/Loader/err_03.png
Normal file
BIN
assets/icons/Loader/err_03.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 385 B |
BIN
assets/icons/Loader/err_04.png
Normal file
BIN
assets/icons/Loader/err_04.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 385 B |
BIN
assets/icons/Loader/err_05.png
Normal file
BIN
assets/icons/Loader/err_05.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 B |
@@ -435,7 +435,6 @@ static bool elf_relocate(ELFFile* elf, ELFSection* s) {
|
|||||||
/************************************ Internal FAP interfaces *************************************/
|
/************************************ Internal FAP interfaces *************************************/
|
||||||
/**************************************************************************************************/
|
/**************************************************************************************************/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SectionTypeERROR = 0,
|
|
||||||
SectionTypeUnused = 1 << 0,
|
SectionTypeUnused = 1 << 0,
|
||||||
SectionTypeData = 1 << 1,
|
SectionTypeData = 1 << 1,
|
||||||
SectionTypeRelData = 1 << 2,
|
SectionTypeRelData = 1 << 2,
|
||||||
@@ -443,8 +442,6 @@ typedef enum {
|
|||||||
SectionTypeStrTab = 1 << 4,
|
SectionTypeStrTab = 1 << 4,
|
||||||
SectionTypeDebugLink = 1 << 5,
|
SectionTypeDebugLink = 1 << 5,
|
||||||
SectionTypeFastRelData = 1 << 6,
|
SectionTypeFastRelData = 1 << 6,
|
||||||
|
|
||||||
SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab,
|
|
||||||
} SectionType;
|
} SectionType;
|
||||||
|
|
||||||
static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) {
|
static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) {
|
||||||
@@ -460,37 +457,62 @@ static bool str_prefix(const char* str, const char* prefix) {
|
|||||||
return strncmp(prefix, str, strlen(prefix)) == 0;
|
return strncmp(prefix, str, strlen(prefix)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* section_header) {
|
typedef enum {
|
||||||
|
ELFLoadSectionResultSuccess,
|
||||||
|
ELFLoadSectionResultNoMemory,
|
||||||
|
ELFLoadSectionResultError,
|
||||||
|
} ELFLoadSectionResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SectionType type;
|
||||||
|
ELFLoadSectionResult result;
|
||||||
|
} SectionTypeInfo;
|
||||||
|
|
||||||
|
static ELFLoadSectionResult
|
||||||
|
elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* section_header) {
|
||||||
if(section_header->sh_size == 0) {
|
if(section_header->sh_size == 0) {
|
||||||
FURI_LOG_D(TAG, "No data for section");
|
FURI_LOG_D(TAG, "No data for section");
|
||||||
return true;
|
return ELFLoadSectionResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t safe_size = section_header->sh_size + 1024;
|
||||||
|
|
||||||
|
furi_kernel_lock();
|
||||||
|
|
||||||
|
if(memmgr_heap_get_max_free_block() < safe_size) {
|
||||||
|
furi_kernel_unlock();
|
||||||
|
FURI_LOG_E(TAG, "Not enough memory to load section data");
|
||||||
|
return ELFLoadSectionResultNoMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
section->data = aligned_malloc(section_header->sh_size, section_header->sh_addralign);
|
section->data = aligned_malloc(section_header->sh_size, section_header->sh_addralign);
|
||||||
section->size = section_header->sh_size;
|
section->size = section_header->sh_size;
|
||||||
|
|
||||||
|
furi_kernel_unlock();
|
||||||
|
|
||||||
if(section_header->sh_type == SHT_NOBITS) {
|
if(section_header->sh_type == SHT_NOBITS) {
|
||||||
// BSS section, no data to load
|
// BSS section, no data to load
|
||||||
return true;
|
return ELFLoadSectionResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((!storage_file_seek(elf->fd, section_header->sh_offset, true)) ||
|
if((!storage_file_seek(elf->fd, section_header->sh_offset, true)) ||
|
||||||
(storage_file_read(elf->fd, section->data, section_header->sh_size) !=
|
(storage_file_read(elf->fd, section->data, section_header->sh_size) !=
|
||||||
section_header->sh_size)) {
|
section_header->sh_size)) {
|
||||||
FURI_LOG_E(TAG, " seek/read fail");
|
FURI_LOG_E(TAG, " seek/read fail");
|
||||||
return false;
|
return ELFLoadSectionResultError;
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "0x%p", section->data);
|
FURI_LOG_D(TAG, "0x%p", section->data);
|
||||||
return true;
|
return ELFLoadSectionResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SectionType elf_preload_section(
|
static SectionTypeInfo elf_preload_section(
|
||||||
ELFFile* elf,
|
ELFFile* elf,
|
||||||
size_t section_idx,
|
size_t section_idx,
|
||||||
Elf32_Shdr* section_header,
|
Elf32_Shdr* section_header,
|
||||||
FuriString* name_string) {
|
FuriString* name_string) {
|
||||||
const char* name = furi_string_get_cstr(name_string);
|
const char* name = furi_string_get_cstr(name_string);
|
||||||
|
SectionTypeInfo info;
|
||||||
|
|
||||||
#ifdef ELF_DEBUG_LOG
|
#ifdef ELF_DEBUG_LOG
|
||||||
// log section name, type and flags
|
// log section name, type and flags
|
||||||
@@ -527,7 +549,10 @@ static SectionType elf_preload_section(
|
|||||||
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") ||
|
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") ||
|
||||||
str_prefix(name, ".fast.rel.ARM.")) {
|
str_prefix(name, ".fast.rel.ARM.")) {
|
||||||
FURI_LOG_D(TAG, "Ignoring ARM section");
|
FURI_LOG_D(TAG, "Ignoring ARM section");
|
||||||
return SectionTypeUnused;
|
|
||||||
|
info.type = SectionTypeUnused;
|
||||||
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load allocable section
|
// Load allocable section
|
||||||
@@ -546,26 +571,32 @@ static SectionType elf_preload_section(
|
|||||||
elf->fini_array = section_p;
|
elf->fini_array = section_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!elf_load_section_data(elf, section_p, section_header)) {
|
info.type = SectionTypeData;
|
||||||
|
info.result = elf_load_section_data(elf, section_p, section_header);
|
||||||
|
|
||||||
|
if(info.result != ELFLoadSectionResultSuccess) {
|
||||||
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
||||||
return SectionTypeERROR;
|
|
||||||
} else {
|
|
||||||
return SectionTypeData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load link info section
|
// Load link info section
|
||||||
if(section_header->sh_flags & SHF_INFO_LINK) {
|
if(section_header->sh_flags & SHF_INFO_LINK) {
|
||||||
|
info.type = SectionTypeRelData;
|
||||||
|
|
||||||
if(str_prefix(name, ".rel")) {
|
if(str_prefix(name, ".rel")) {
|
||||||
name = name + strlen(".rel");
|
name = name + strlen(".rel");
|
||||||
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
||||||
section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel);
|
section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel);
|
||||||
section_p->rel_offset = section_header->sh_offset;
|
section_p->rel_offset = section_header->sh_offset;
|
||||||
return SectionTypeRelData;
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
} else {
|
} else {
|
||||||
FURI_LOG_E(TAG, "Unknown link info section '%s'", name);
|
FURI_LOG_E(TAG, "Unknown link info section '%s'", name);
|
||||||
return SectionTypeERROR;
|
info.result = ELFLoadSectionResultError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load fast rel section
|
// Load fast rel section
|
||||||
@@ -574,13 +605,16 @@ static SectionType elf_preload_section(
|
|||||||
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
||||||
section_p->fast_rel = malloc(sizeof(ELFSection));
|
section_p->fast_rel = malloc(sizeof(ELFSection));
|
||||||
|
|
||||||
if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) {
|
info.type = SectionTypeFastRelData;
|
||||||
|
info.result = elf_load_section_data(elf, section_p->fast_rel, section_header);
|
||||||
|
|
||||||
|
if(info.result != ELFLoadSectionResultSuccess) {
|
||||||
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
||||||
return SectionTypeERROR;
|
} else {
|
||||||
|
FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name);
|
return info;
|
||||||
return SectionTypeFastRelData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load symbol table
|
// Load symbol table
|
||||||
@@ -588,27 +622,39 @@ static SectionType elf_preload_section(
|
|||||||
FURI_LOG_D(TAG, "Found .symtab section");
|
FURI_LOG_D(TAG, "Found .symtab section");
|
||||||
elf->symbol_table = section_header->sh_offset;
|
elf->symbol_table = section_header->sh_offset;
|
||||||
elf->symbol_count = section_header->sh_size / sizeof(Elf32_Sym);
|
elf->symbol_count = section_header->sh_size / sizeof(Elf32_Sym);
|
||||||
return SectionTypeSymTab;
|
|
||||||
|
info.type = SectionTypeSymTab;
|
||||||
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load string table
|
// Load string table
|
||||||
if(strcmp(name, ".strtab") == 0) {
|
if(strcmp(name, ".strtab") == 0) {
|
||||||
FURI_LOG_D(TAG, "Found .strtab section");
|
FURI_LOG_D(TAG, "Found .strtab section");
|
||||||
elf->symbol_table_strings = section_header->sh_offset;
|
elf->symbol_table_strings = section_header->sh_offset;
|
||||||
return SectionTypeStrTab;
|
|
||||||
|
info.type = SectionTypeStrTab;
|
||||||
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load debug link section
|
// Load debug link section
|
||||||
if(strcmp(name, ".gnu_debuglink") == 0) {
|
if(strcmp(name, ".gnu_debuglink") == 0) {
|
||||||
FURI_LOG_D(TAG, "Found .gnu_debuglink section");
|
FURI_LOG_D(TAG, "Found .gnu_debuglink section");
|
||||||
|
info.type = SectionTypeDebugLink;
|
||||||
|
|
||||||
if(elf_load_debug_link(elf, section_header)) {
|
if(elf_load_debug_link(elf, section_header)) {
|
||||||
return SectionTypeDebugLink;
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
|
return info;
|
||||||
} else {
|
} else {
|
||||||
return SectionTypeERROR;
|
info.result = ELFLoadSectionResultError;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SectionTypeUnused;
|
info.type = SectionTypeUnused;
|
||||||
|
info.result = ELFLoadSectionResultSuccess;
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) {
|
static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) {
|
||||||
@@ -836,35 +882,57 @@ bool elf_file_open(ELFFile* elf, const char* path) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool elf_file_load_section_table(ELFFile* elf) {
|
ElfLoadSectionTableResult elf_file_load_section_table(ELFFile* elf) {
|
||||||
SectionType loaded_sections = SectionTypeERROR;
|
SectionType loaded_sections = 0;
|
||||||
FuriString* name = furi_string_alloc();
|
FuriString* name = furi_string_alloc();
|
||||||
|
ElfLoadSectionTableResult result = ElfLoadSectionTableResultSuccess;
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Scan ELF indexs...");
|
FURI_LOG_D(TAG, "Scan ELF indexs...");
|
||||||
// TODO FL-3526: why we start from 1?
|
|
||||||
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
|
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
|
||||||
Elf32_Shdr section_header;
|
Elf32_Shdr section_header;
|
||||||
|
|
||||||
furi_string_reset(name);
|
furi_string_reset(name);
|
||||||
if(!elf_read_section(elf, section_idx, §ion_header, name)) {
|
if(!elf_read_section(elf, section_idx, §ion_header, name)) {
|
||||||
loaded_sections = SectionTypeERROR;
|
loaded_sections = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FURI_LOG_D(
|
FURI_LOG_D(
|
||||||
TAG, "Preloading data for section #%d %s", section_idx, furi_string_get_cstr(name));
|
TAG, "Preloading data for section #%d %s", section_idx, furi_string_get_cstr(name));
|
||||||
SectionType section_type = elf_preload_section(elf, section_idx, §ion_header, name);
|
SectionTypeInfo section_type_info =
|
||||||
loaded_sections |= section_type;
|
elf_preload_section(elf, section_idx, §ion_header, name);
|
||||||
|
loaded_sections |= section_type_info.type;
|
||||||
|
|
||||||
if(section_type == SectionTypeERROR) {
|
if(section_type_info.result != ELFLoadSectionResultSuccess) {
|
||||||
loaded_sections = SectionTypeERROR;
|
if(section_type_info.result == ELFLoadSectionResultNoMemory) {
|
||||||
|
FURI_LOG_E(TAG, "Not enough memory");
|
||||||
|
result = ElfLoadSectionTableResultNoMemory;
|
||||||
|
} else if(section_type_info.result == ELFLoadSectionResultError) {
|
||||||
|
FURI_LOG_E(TAG, "Error loading section");
|
||||||
|
result = ElfLoadSectionTableResultError;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded_sections = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
furi_string_free(name);
|
furi_string_free(name);
|
||||||
|
|
||||||
return IS_FLAGS_SET(loaded_sections, SectionTypeValid);
|
if(result != ElfLoadSectionTableResultSuccess) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
bool sections_valid =
|
||||||
|
IS_FLAGS_SET(loaded_sections, SectionTypeSymTab | SectionTypeStrTab) |
|
||||||
|
IS_FLAGS_SET(loaded_sections, SectionTypeFastRelData);
|
||||||
|
if(sections_valid) {
|
||||||
|
return ElfLoadSectionTableResultSuccess;
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(TAG, "No valid sections found");
|
||||||
|
return ElfLoadSectionTableResultError;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ElfProcessSectionResult elf_process_section(
|
ElfProcessSectionResult elf_process_section(
|
||||||
@@ -877,7 +945,6 @@ ElfProcessSectionResult elf_process_section(
|
|||||||
Elf32_Shdr section_header;
|
Elf32_Shdr section_header;
|
||||||
|
|
||||||
// find section
|
// find section
|
||||||
// TODO FL-3526: why we start from 1?
|
|
||||||
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
|
for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) {
|
||||||
furi_string_reset(section_name);
|
furi_string_reset(section_name);
|
||||||
if(!elf_read_section(elf, section_idx, §ion_header, section_name)) {
|
if(!elf_read_section(elf, section_idx, §ion_header, section_name)) {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ typedef struct {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ELFFileLoadStatusSuccess = 0,
|
ELFFileLoadStatusSuccess = 0,
|
||||||
ELFFileLoadStatusUnspecifiedError,
|
ELFFileLoadStatusUnspecifiedError,
|
||||||
ELFFileLoadStatusNoFreeMemory,
|
|
||||||
ELFFileLoadStatusMissingImports,
|
ELFFileLoadStatusMissingImports,
|
||||||
} ELFFileLoadStatus;
|
} ELFFileLoadStatus;
|
||||||
|
|
||||||
@@ -43,6 +42,12 @@ typedef enum {
|
|||||||
ElfProcessSectionResultSuccess,
|
ElfProcessSectionResultSuccess,
|
||||||
} ElfProcessSectionResult;
|
} ElfProcessSectionResult;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ElfLoadSectionTableResultError,
|
||||||
|
ElfLoadSectionTableResultNoMemory,
|
||||||
|
ElfLoadSectionTableResultSuccess,
|
||||||
|
} ElfLoadSectionTableResult;
|
||||||
|
|
||||||
typedef bool(ElfProcessSection)(File* file, size_t offset, size_t size, void* context);
|
typedef bool(ElfProcessSection)(File* file, size_t offset, size_t size, void* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,9 +75,9 @@ bool elf_file_open(ELFFile* elf_file, const char* path);
|
|||||||
/**
|
/**
|
||||||
* @brief Load ELF file section table (load stage #1)
|
* @brief Load ELF file section table (load stage #1)
|
||||||
* @param elf_file
|
* @param elf_file
|
||||||
* @return bool
|
* @return ElfLoadSectionTableResult
|
||||||
*/
|
*/
|
||||||
bool elf_file_load_section_table(ELFFile* elf_file);
|
ElfLoadSectionTableResult elf_file_load_section_table(ELFFile* elf_file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load and relocate ELF file sections (load stage #2)
|
* @brief Load and relocate ELF file sections (load stage #2)
|
||||||
|
|||||||
@@ -161,8 +161,11 @@ static FlipperApplicationPreloadStatus
|
|||||||
// if we are loading full file
|
// if we are loading full file
|
||||||
if(load_full) {
|
if(load_full) {
|
||||||
// load section table
|
// load section table
|
||||||
if(!elf_file_load_section_table(app->elf)) {
|
ElfLoadSectionTableResult load_result = elf_file_load_section_table(app->elf);
|
||||||
|
if(load_result == ElfLoadSectionTableResultError) {
|
||||||
return FlipperApplicationPreloadStatusInvalidFile;
|
return FlipperApplicationPreloadStatusInvalidFile;
|
||||||
|
} else if(load_result == ElfLoadSectionTableResultNoMemory) {
|
||||||
|
return FlipperApplicationPreloadStatusNotEnoughMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// load assets section
|
// load assets section
|
||||||
@@ -219,8 +222,6 @@ FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplicatio
|
|||||||
elf_file_init_debug_info(app->elf, &app->state);
|
elf_file_init_debug_info(app->elf, &app->state);
|
||||||
flipper_application_list_add_app(app);
|
flipper_application_list_add_app(app);
|
||||||
return FlipperApplicationLoadStatusSuccess;
|
return FlipperApplicationLoadStatusSuccess;
|
||||||
case ELFFileLoadStatusNoFreeMemory:
|
|
||||||
return FlipperApplicationLoadStatusNoFreeMemory;
|
|
||||||
case ELFFileLoadStatusMissingImports:
|
case ELFFileLoadStatusMissingImports:
|
||||||
return FlipperApplicationLoadStatusMissingImports;
|
return FlipperApplicationLoadStatusMissingImports;
|
||||||
default:
|
default:
|
||||||
@@ -272,38 +273,38 @@ FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char
|
|||||||
return app->thread;
|
return app->thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* preload_status_strings[] = {
|
|
||||||
[FlipperApplicationPreloadStatusSuccess] = "Success",
|
|
||||||
[FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error",
|
|
||||||
[FlipperApplicationPreloadStatusInvalidFile] = "Invalid file",
|
|
||||||
[FlipperApplicationPreloadStatusInvalidManifest] = "Invalid file manifest",
|
|
||||||
[FlipperApplicationPreloadStatusApiTooOld] =
|
|
||||||
"Update Application to use with this Firmware (ApiTooOld)",
|
|
||||||
[FlipperApplicationPreloadStatusApiTooNew] =
|
|
||||||
"Update Firmware to use with this Application (ApiTooNew)",
|
|
||||||
[FlipperApplicationPreloadStatusTargetMismatch] = "Hardware target mismatch",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* load_status_strings[] = {
|
|
||||||
[FlipperApplicationLoadStatusSuccess] = "Success",
|
|
||||||
[FlipperApplicationLoadStatusUnspecifiedError] = "Unknown error",
|
|
||||||
[FlipperApplicationLoadStatusNoFreeMemory] = "Out of memory",
|
|
||||||
[FlipperApplicationLoadStatusMissingImports] =
|
|
||||||
"Update Firmware to use with this Application (MissingImports)",
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
|
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status) {
|
||||||
if(status >= COUNT_OF(preload_status_strings) || preload_status_strings[status] == NULL) {
|
switch(status) {
|
||||||
return "Unknown error";
|
case FlipperApplicationPreloadStatusSuccess:
|
||||||
|
return "Success";
|
||||||
|
case FlipperApplicationPreloadStatusInvalidFile:
|
||||||
|
return "Invalid file";
|
||||||
|
case FlipperApplicationPreloadStatusNotEnoughMemory:
|
||||||
|
return "Not enough memory";
|
||||||
|
case FlipperApplicationPreloadStatusInvalidManifest:
|
||||||
|
return "Invalid file manifest";
|
||||||
|
case FlipperApplicationPreloadStatusApiTooOld:
|
||||||
|
return "Update Application to use with this Firmware (ApiTooOld)";
|
||||||
|
case FlipperApplicationPreloadStatusApiTooNew:
|
||||||
|
return "Update Firmware to use with this Application (ApiTooNew)";
|
||||||
|
case FlipperApplicationPreloadStatusTargetMismatch:
|
||||||
|
return "Hardware target mismatch";
|
||||||
}
|
}
|
||||||
return preload_status_strings[status];
|
|
||||||
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
|
const char* flipper_application_load_status_to_string(FlipperApplicationLoadStatus status) {
|
||||||
if(status >= COUNT_OF(load_status_strings) || load_status_strings[status] == NULL) {
|
switch(status) {
|
||||||
|
case FlipperApplicationLoadStatusSuccess:
|
||||||
|
return "Success";
|
||||||
|
case FlipperApplicationLoadStatusUnspecifiedError:
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
|
case FlipperApplicationLoadStatusMissingImports:
|
||||||
|
return "Update Firmware to use with this Application (MissingImports)";
|
||||||
}
|
}
|
||||||
return load_status_strings[status];
|
|
||||||
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
const FlipperAppPluginDescriptor*
|
const FlipperAppPluginDescriptor*
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ extern "C" {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FlipperApplicationPreloadStatusSuccess = 0,
|
FlipperApplicationPreloadStatusSuccess = 0,
|
||||||
FlipperApplicationPreloadStatusUnspecifiedError,
|
|
||||||
FlipperApplicationPreloadStatusInvalidFile,
|
FlipperApplicationPreloadStatusInvalidFile,
|
||||||
|
FlipperApplicationPreloadStatusNotEnoughMemory,
|
||||||
FlipperApplicationPreloadStatusInvalidManifest,
|
FlipperApplicationPreloadStatusInvalidManifest,
|
||||||
FlipperApplicationPreloadStatusApiTooOld,
|
FlipperApplicationPreloadStatusApiTooOld,
|
||||||
FlipperApplicationPreloadStatusApiTooNew,
|
FlipperApplicationPreloadStatusApiTooNew,
|
||||||
@@ -29,7 +29,6 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
FlipperApplicationLoadStatusSuccess = 0,
|
FlipperApplicationLoadStatusSuccess = 0,
|
||||||
FlipperApplicationLoadStatusUnspecifiedError,
|
FlipperApplicationLoadStatusUnspecifiedError,
|
||||||
FlipperApplicationLoadStatusNoFreeMemory,
|
|
||||||
FlipperApplicationLoadStatusMissingImports,
|
FlipperApplicationLoadStatusMissingImports,
|
||||||
} FlipperApplicationLoadStatus;
|
} FlipperApplicationLoadStatus;
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ static void nfc_generate_mf_ul_orig(NfcDevice* nfc_device) {
|
|||||||
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
MfUltralightData* mfu_data = mf_ultralight_alloc();
|
||||||
nfc_generate_mf_ul_common(mfu_data);
|
nfc_generate_mf_ul_common(mfu_data);
|
||||||
|
|
||||||
mfu_data->type = MfUltralightTypeUnknown;
|
mfu_data->type = MfUltralightTypeOrigin;
|
||||||
mfu_data->pages_total = 16;
|
mfu_data->pages_total = 16;
|
||||||
mfu_data->pages_read = 16;
|
mfu_data->pages_read = 16;
|
||||||
memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage));
|
memset(&mfu_data->page[4], 0xff, sizeof(MfUltralightPage));
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ typedef struct {
|
|||||||
static const uint32_t mf_ultralight_data_format_version = 2;
|
static const uint32_t mf_ultralight_data_format_version = 2;
|
||||||
|
|
||||||
static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = {
|
static const MfUltralightFeatures mf_ultralight_features[MfUltralightTypeNum] = {
|
||||||
[MfUltralightTypeUnknown] =
|
[MfUltralightTypeOrigin] =
|
||||||
{
|
{
|
||||||
.device_name = "Mifare Ultralight",
|
.device_name = "Mifare Ultralight",
|
||||||
.total_pages = 16,
|
.total_pages = 16,
|
||||||
@@ -215,7 +215,7 @@ static const char*
|
|||||||
mf_ultralight_get_device_name_by_type(MfUltralightType type, NfcDeviceNameType name_type) {
|
mf_ultralight_get_device_name_by_type(MfUltralightType type, NfcDeviceNameType name_type) {
|
||||||
if(name_type == NfcDeviceNameTypeShort &&
|
if(name_type == NfcDeviceNameTypeShort &&
|
||||||
(type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21)) {
|
(type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21)) {
|
||||||
type = MfUltralightTypeUnknown;
|
type = MfUltralightTypeOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mf_ultralight_features[type].device_name;
|
return mf_ultralight_features[type].device_name;
|
||||||
@@ -512,7 +512,7 @@ Iso14443_3aData* mf_ultralight_get_base_data(const MfUltralightData* data) {
|
|||||||
MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) {
|
MfUltralightType mf_ultralight_get_type_by_version(MfUltralightVersion* version) {
|
||||||
furi_check(version);
|
furi_check(version);
|
||||||
|
|
||||||
MfUltralightType type = MfUltralightTypeUnknown;
|
MfUltralightType type = MfUltralightTypeOrigin;
|
||||||
|
|
||||||
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
|
if(version->storage_size == 0x0B || version->storage_size == 0x00) {
|
||||||
type = MfUltralightTypeUL11;
|
type = MfUltralightTypeUL11;
|
||||||
@@ -575,12 +575,14 @@ uint8_t mf_ultralight_get_write_end_page(MfUltralightType type) {
|
|||||||
furi_assert(
|
furi_assert(
|
||||||
type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21 ||
|
type == MfUltralightTypeUL11 || type == MfUltralightTypeUL21 ||
|
||||||
type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
|
type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
|
||||||
type == MfUltralightTypeNTAG216);
|
type == MfUltralightTypeNTAG216 || type == MfUltralightTypeOrigin);
|
||||||
|
|
||||||
uint8_t end_page = mf_ultralight_get_config_page_num(type);
|
uint8_t end_page = mf_ultralight_get_config_page_num(type);
|
||||||
if(type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
|
if(type == MfUltralightTypeNTAG213 || type == MfUltralightTypeNTAG215 ||
|
||||||
type == MfUltralightTypeNTAG216) {
|
type == MfUltralightTypeNTAG216) {
|
||||||
end_page -= 1;
|
end_page -= 1;
|
||||||
|
} else if(type == MfUltralightTypeOrigin) {
|
||||||
|
end_page = mf_ultralight_features[type].total_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
return end_page;
|
return end_page;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ typedef enum {
|
|||||||
} MfUltralightError;
|
} MfUltralightError;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MfUltralightTypeUnknown,
|
MfUltralightTypeOrigin,
|
||||||
MfUltralightTypeNTAG203,
|
MfUltralightTypeNTAG203,
|
||||||
MfUltralightTypeMfulC,
|
MfUltralightTypeMfulC,
|
||||||
MfUltralightTypeUL11,
|
MfUltralightTypeUL11,
|
||||||
|
|||||||
@@ -281,12 +281,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller
|
|||||||
} else {
|
} else {
|
||||||
FURI_LOG_D(TAG, "Original Ultralight detected");
|
FURI_LOG_D(TAG, "Original Ultralight detected");
|
||||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||||
instance->data->type = MfUltralightTypeUnknown;
|
instance->data->type = MfUltralightTypeOrigin;
|
||||||
if(instance->mode == MfUltralightPollerModeWrite) {
|
|
||||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch;
|
|
||||||
instance->callback(instance->general_event, instance->context);
|
|
||||||
next_state = MfUltralightPollerStateWriteFail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
instance->state = next_state;
|
instance->state = next_state;
|
||||||
|
|
||||||
@@ -575,11 +570,13 @@ static NfcCommand mf_ultralight_poller_handler_request_write_data(MfUltralightPo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth)) {
|
||||||
if(!instance->auth_context.auth_success) {
|
if(!instance->auth_context.auth_success) {
|
||||||
FURI_LOG_D(TAG, "Unknown password");
|
FURI_LOG_D(TAG, "Unknown password");
|
||||||
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
|
instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MfUltralightPage staticlock_page = tag_data->page[2];
|
const MfUltralightPage staticlock_page = tag_data->page[2];
|
||||||
if(staticlock_page.data[2] != 0 || staticlock_page.data[3] != 0) {
|
if(staticlock_page.data[2] != 0 || staticlock_page.data[3] != 0) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,65.0,,
|
Version,+,66.0,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,65.0,,
|
Version,+,66.0,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
|
|||||||
|
Reference in New Issue
Block a user