From e6d22ed1475a05db858b39b95ae9933bbd2252ca Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Mon, 26 Sep 2022 00:11:29 +1000 Subject: [PATCH 1/3] ELF-Loader: C++ plugin support, loader overhaul. (#1744) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fap-loader: load all code and data sections * fap-loader: relocate all code and data sections * fap-loader: remove old elf loader * fap-loader: new jmp call relocation * openocd: resume on detach * fap-loader: trampoline for big jumps * fap-loader: rename cache * fap-loader: init_array support * fap-loader: untangled flipper_application into separate entities * fap-loader: fix debug * fap-loader: optimize section container * fap-loader: optimize key for section container * fap-loader: disable debug log * documentation * F7: bump api symbols version * Lib: cleanup elf_file.c Co-authored-by: あく --- applications/main/fap_loader/fap_loader_app.c | 2 +- debug/flipperapps.py | 8 +- debug/stm32wbx.cfg | 4 + firmware/targets/f7/api_symbols.csv | 8 +- .../application_manifest.c | 21 + .../application_manifest.h | 25 + .../elf/elf_api_interface.h | 2 +- lib/flipper_application/elf/elf_file.c | 794 ++++++++++++++++++ lib/flipper_application/elf/elf_file.h | 127 +++ lib/flipper_application/elf/elf_file_i.h | 46 + .../flipper_applicaiton_i.c | 477 ----------- lib/flipper_application/flipper_application.c | 97 ++- lib/flipper_application/flipper_application.h | 33 +- .../flipper_application_i.h | 99 --- 14 files changed, 1094 insertions(+), 649 deletions(-) create mode 100644 lib/flipper_application/application_manifest.c create mode 100644 lib/flipper_application/elf/elf_file.c create mode 100644 lib/flipper_application/elf/elf_file.h create mode 100644 lib/flipper_application/elf/elf_file_i.h delete mode 100644 lib/flipper_application/flipper_applicaiton_i.c delete mode 100644 lib/flipper_application/flipper_application_i.h diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index 14da2f320..9050ddf78 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -25,7 +25,7 @@ static bool FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(app, string_get_cstr(path)); + flipper_application_preload_manifest(app, string_get_cstr(path)); bool load_success = false; diff --git a/debug/flipperapps.py b/debug/flipperapps.py index c8d3fcdb9..8e1aa2daf 100644 --- a/debug/flipperapps.py +++ b/debug/flipperapps.py @@ -64,7 +64,7 @@ class AppState: def is_loaded_in_gdb(self, gdb_app) -> bool: # Avoid constructing full app wrapper for comparison - return self.entry_address == int(gdb_app["entry"]) + return self.entry_address == int(gdb_app["state"]["entry"]) @staticmethod def parse_debug_link_data(section_data: bytes) -> Tuple[str, int]: @@ -78,13 +78,13 @@ class AppState: @staticmethod def from_gdb(gdb_app: "AppState") -> "AppState": state = AppState(str(gdb_app["manifest"]["name"].string())) - state.entry_address = int(gdb_app["entry"]) + state.entry_address = int(gdb_app["state"]["entry"]) app_state = gdb_app["state"] - if debug_link_size := int(app_state["debug_link_size"]): + if debug_link_size := int(app_state["debug_link_info"]["debug_link_size"]): debug_link_data = ( gdb.selected_inferior() - .read_memory(int(app_state["debug_link"]), debug_link_size) + .read_memory(int(app_state["debug_link_info"]["debug_link"]), debug_link_size) .tobytes() ) state.debug_link_elf, state.debug_link_crc = AppState.parse_debug_link_data( diff --git a/debug/stm32wbx.cfg b/debug/stm32wbx.cfg index f100c3ccd..ba383831b 100644 --- a/debug/stm32wbx.cfg +++ b/debug/stm32wbx.cfg @@ -101,3 +101,7 @@ $_TARGETNAME configure -event trace-config { # assignment mmw 0xE0042004 0x00000020 0 } + +$_TARGETNAME configure -event gdb-detach { + resume +} \ No newline at end of file diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index ac4df046d..39365c397 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,1.9,, +Version,+,1.10,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -779,13 +779,13 @@ Function,-,fiprintf,int,"FILE*, const char*, ..." Function,-,fiscanf,int,"FILE*, const char*, ..." Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*" Function,+,flipper_application_free,void,FlipperApplication* -Function,-,flipper_application_get_entry_address,const void*,FlipperApplication* Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* -Function,-,flipper_application_get_state,const FlipperApplicationState*,FlipperApplication* -Function,-,flipper_application_get_thread,FuriThread*,FlipperApplication* Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus +Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*" +Function,+,flipper_application_manifest_is_valid,_Bool,const FlipperApplicationManifest* Function,+,flipper_application_map_to_memory,FlipperApplicationLoadStatus,FlipperApplication* Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" +Function,+,flipper_application_preload_manifest,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" Function,-,flipper_application_preload_status_to_string,const char*,FlipperApplicationPreloadStatus Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* diff --git a/lib/flipper_application/application_manifest.c b/lib/flipper_application/application_manifest.c new file mode 100644 index 000000000..ab92e4930 --- /dev/null +++ b/lib/flipper_application/application_manifest.c @@ -0,0 +1,21 @@ +#include "application_manifest.h" + +bool flipper_application_manifest_is_valid(const FlipperApplicationManifest* manifest) { + if((manifest->base.manifest_magic != FAP_MANIFEST_MAGIC) || + (manifest->base.manifest_version != FAP_MANIFEST_SUPPORTED_VERSION)) { + return false; + } + + return true; +} + +bool flipper_application_manifest_is_compatible( + const FlipperApplicationManifest* manifest, + const ElfApiInterface* api_interface) { + if(manifest->base.api_version.major != api_interface->api_version_major /* || + manifest->base.api_version.minor > app->api_interface->api_version_minor */) { + return false; + } + + return true; +} diff --git a/lib/flipper_application/application_manifest.h b/lib/flipper_application/application_manifest.h index 6aa20e481..f46d44fd7 100644 --- a/lib/flipper_application/application_manifest.h +++ b/lib/flipper_application/application_manifest.h @@ -1,6 +1,12 @@ +/** + * @file application_manifest.h + * Flipper application manifest + */ #pragma once #include +#include +#include "elf/elf_api_interface.h" #ifdef __cplusplus extern "C" { @@ -40,6 +46,25 @@ typedef FlipperApplicationManifestV1 FlipperApplicationManifest; #pragma pack(pop) +/** + * @brief Check if manifest is valid + * + * @param manifest + * @return bool + */ +bool flipper_application_manifest_is_valid(const FlipperApplicationManifest* manifest); + +/** + * @brief Check if manifest is compatible with current ELF API interface + * + * @param manifest + * @param api_interface + * @return bool + */ +bool flipper_application_manifest_is_compatible( + const FlipperApplicationManifest* manifest, + const ElfApiInterface* api_interface); + #ifdef __cplusplus } #endif diff --git a/lib/flipper_application/elf/elf_api_interface.h b/lib/flipper_application/elf/elf_api_interface.h index 505f4f718..ca31fc483 100644 --- a/lib/flipper_application/elf/elf_api_interface.h +++ b/lib/flipper_application/elf/elf_api_interface.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #define ELF_INVALID_ADDRESS 0xFFFFFFFF diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c new file mode 100644 index 000000000..202d0a875 --- /dev/null +++ b/lib/flipper_application/elf/elf_file.c @@ -0,0 +1,794 @@ +#include +#include "elf_file.h" +#include "elf_file_i.h" +#include "elf_api_interface.h" + +#define TAG "elf" + +#define ELF_NAME_BUFFER_LEN 32 +#define SECTION_OFFSET(e, n) (e->section_table + n * sizeof(Elf32_Shdr)) +#define IS_FLAGS_SET(v, m) ((v & m) == m) +#define RESOLVER_THREAD_YIELD_STEP 30 + +// #define ELF_DEBUG_LOG 1 + +#ifndef ELF_DEBUG_LOG +#undef FURI_LOG_D +#define FURI_LOG_D(...) +#endif + +#define TRAMPOLINE_CODE_SIZE 6 + +/** +ldr r12, [pc, #2] +bx r12 +*/ +const uint8_t trampoline_code_little_endian[TRAMPOLINE_CODE_SIZE] = + {0xdf, 0xf8, 0x02, 0xc0, 0x60, 0x47}; + +typedef struct { + uint8_t code[TRAMPOLINE_CODE_SIZE]; + uint32_t addr; +} __attribute__((packed)) JMPTrampoline; + +/**************************************************************************************************/ +/********************************************* Caches *********************************************/ +/**************************************************************************************************/ + +static bool address_cache_get(AddressCache_t cache, int symEntry, Elf32_Addr* symAddr) { + Elf32_Addr* addr = AddressCache_get(cache, symEntry); + if(addr) { + *symAddr = *addr; + return true; + } else { + return false; + } +} + +static void address_cache_put(AddressCache_t cache, int symEntry, Elf32_Addr symAddr) { + AddressCache_set_at(cache, symEntry, symAddr); +} + +/**************************************************************************************************/ +/********************************************** ELF ***********************************************/ +/**************************************************************************************************/ + +static ELFSection* elf_file_get_section(ELFFile* elf, const char* name) { + return ELFSectionDict_get(elf->sections, name); +} + +static void elf_file_put_section(ELFFile* elf, const char* name, ELFSection* section) { + ELFSectionDict_set_at(elf->sections, strdup(name), *section); +} + +static bool elf_read_string_from_offset(ELFFile* elf, off_t offset, string_t name) { + bool result = false; + + off_t old = storage_file_tell(elf->fd); + + do { + if(!storage_file_seek(elf->fd, offset, true)) break; + + char buffer[ELF_NAME_BUFFER_LEN + 1]; + buffer[ELF_NAME_BUFFER_LEN] = 0; + + while(true) { + uint16_t read = storage_file_read(elf->fd, buffer, ELF_NAME_BUFFER_LEN); + string_cat_str(name, buffer); + if(strlen(buffer) < ELF_NAME_BUFFER_LEN) { + result = true; + break; + } + + if(storage_file_get_error(elf->fd) != FSE_OK || read == 0) break; + } + + } while(false); + storage_file_seek(elf->fd, old, true); + + return result; +} + +static bool elf_read_section_name(ELFFile* elf, off_t offset, string_t name) { + return elf_read_string_from_offset(elf, elf->section_table_strings + offset, name); +} + +static bool elf_read_symbol_name(ELFFile* elf, off_t offset, string_t name) { + return elf_read_string_from_offset(elf, elf->symbol_table_strings + offset, name); +} + +static bool elf_read_section_header(ELFFile* elf, size_t section_idx, Elf32_Shdr* section_header) { + off_t offset = SECTION_OFFSET(elf, section_idx); + return storage_file_seek(elf->fd, offset, true) && + storage_file_read(elf->fd, section_header, sizeof(Elf32_Shdr)) == sizeof(Elf32_Shdr); +} + +static bool + elf_read_section(ELFFile* elf, size_t section_idx, Elf32_Shdr* section_header, string_t name) { + if(!elf_read_section_header(elf, section_idx, section_header)) { + return false; + } + + if(section_header->sh_name && !elf_read_section_name(elf, section_header->sh_name, name)) { + return false; + } + + return true; +} + +static bool elf_read_symbol(ELFFile* elf, int n, Elf32_Sym* sym, string_t name) { + bool success = false; + off_t old = storage_file_tell(elf->fd); + off_t pos = elf->symbol_table + n * sizeof(Elf32_Sym); + if(storage_file_seek(elf->fd, pos, true) && + storage_file_read(elf->fd, sym, sizeof(Elf32_Sym)) == sizeof(Elf32_Sym)) { + if(sym->st_name) + success = elf_read_symbol_name(elf, sym->st_name, name); + else { + Elf32_Shdr shdr; + success = elf_read_section(elf, sym->st_shndx, &shdr, name); + } + } + storage_file_seek(elf->fd, old, true); + return success; +} + +static ELFSection* elf_section_of(ELFFile* elf, int index) { + ELFSectionDict_it_t it; + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { + ELFSectionDict_itref_t* itref = ELFSectionDict_ref(it); + if(itref->value.sec_idx == index) { + return &itref->value; + } + } + + return NULL; +} + +static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) { + if(sym->st_shndx == SHN_UNDEF) { + Elf32_Addr addr = 0; + if(elf->api_interface->resolver_callback(sName, &addr)) { + return addr; + } + } else { + ELFSection* symSec = elf_section_of(elf, sym->st_shndx); + if(symSec) { + return ((Elf32_Addr)symSec->data) + sym->st_value; + } + } + FURI_LOG_D(TAG, " Can not find address for symbol %s", sName); + return ELF_INVALID_ADDRESS; +} + +__attribute__((unused)) static const char* elf_reloc_type_to_str(int symt) { +#define STRCASE(name) \ + case name: \ + return #name; + switch(symt) { + STRCASE(R_ARM_NONE) + STRCASE(R_ARM_TARGET1) + STRCASE(R_ARM_ABS32) + STRCASE(R_ARM_THM_PC22) + STRCASE(R_ARM_THM_JUMP24) + default: + return "R_"; + } +#undef STRCASE +} + +static JMPTrampoline* elf_create_trampoline(Elf32_Addr addr) { + JMPTrampoline* trampoline = malloc(sizeof(JMPTrampoline)); + memcpy(trampoline->code, trampoline_code_little_endian, TRAMPOLINE_CODE_SIZE); + trampoline->addr = addr; + return trampoline; +} + +static void elf_relocate_jmp_call(ELFFile* elf, Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { + int offset, hi, lo, s, j1, j2, i1, i2, imm10, imm11; + int to_thumb, is_call, blx_bit = 1 << 12; + + /* Get initial offset */ + hi = ((uint16_t*)relAddr)[0]; + lo = ((uint16_t*)relAddr)[1]; + s = (hi >> 10) & 1; + j1 = (lo >> 13) & 1; + j2 = (lo >> 11) & 1; + i1 = (j1 ^ s) ^ 1; + i2 = (j2 ^ s) ^ 1; + imm10 = hi & 0x3ff; + imm11 = lo & 0x7ff; + offset = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); + if(offset & 0x01000000) offset -= 0x02000000; + + to_thumb = symAddr & 1; + is_call = (type == R_ARM_THM_PC22); + + /* Store offset */ + int offset_copy = offset; + + /* Compute final offset */ + offset += symAddr - relAddr; + if(!to_thumb && is_call) { + blx_bit = 0; /* bl -> blx */ + offset = (offset + 3) & -4; /* Compute offset from aligned PC */ + } + + /* Check that relocation is possible + * offset must not be out of range + * if target is to be entered in arm mode: + - bit 1 must not set + - instruction must be a call (bl) or a jump to PLT */ + if(!to_thumb || offset >= 0x1000000 || offset < -0x1000000) { + if(to_thumb || (symAddr & 2) || (!is_call)) { + FURI_LOG_D( + TAG, + "can't relocate value at %x, %s, doing trampoline", + relAddr, + elf_reloc_type_to_str(type)); + + Elf32_Addr addr; + if(!address_cache_get(elf->trampoline_cache, symAddr, &addr)) { + addr = (Elf32_Addr)elf_create_trampoline(symAddr); + address_cache_put(elf->trampoline_cache, symAddr, addr); + } + + offset = offset_copy; + offset += (int)addr - relAddr; + if(!to_thumb && is_call) { + blx_bit = 0; /* bl -> blx */ + offset = (offset + 3) & -4; /* Compute offset from aligned PC */ + } + } + } + + /* Compute and store final offset */ + s = (offset >> 24) & 1; + i1 = (offset >> 23) & 1; + i2 = (offset >> 22) & 1; + j1 = s ^ (i1 ^ 1); + j2 = s ^ (i2 ^ 1); + imm10 = (offset >> 12) & 0x3ff; + imm11 = (offset >> 1) & 0x7ff; + (*(uint16_t*)relAddr) = (uint16_t)((hi & 0xf800) | (s << 10) | imm10); + (*(uint16_t*)(relAddr + 2)) = + (uint16_t)((lo & 0xc000) | (j1 << 13) | blx_bit | (j2 << 11) | imm11); +} + +static bool elf_relocate_symbol(ELFFile* elf, Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { + switch(type) { + case R_ARM_TARGET1: + case R_ARM_ABS32: + *((uint32_t*)relAddr) += symAddr; + FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); + break; + case R_ARM_THM_PC22: + case R_ARM_THM_JUMP24: + elf_relocate_jmp_call(elf, relAddr, type, symAddr); + FURI_LOG_D( + TAG, " R_ARM_THM_CALL/JMP relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); + break; + default: + FURI_LOG_E(TAG, " Undefined relocation %d", type); + return false; + } + return true; +} + +static bool elf_relocate(ELFFile* elf, Elf32_Shdr* h, ELFSection* s) { + if(s->data) { + Elf32_Rel rel; + size_t relEntries = h->sh_size / sizeof(rel); + size_t relCount; + (void)storage_file_seek(elf->fd, h->sh_offset, true); + FURI_LOG_D(TAG, " Offset Info Type Name"); + + int relocate_result = true; + string_t symbol_name; + string_init(symbol_name); + + for(relCount = 0; relCount < relEntries; relCount++) { + if(relCount % RESOLVER_THREAD_YIELD_STEP == 0) { + FURI_LOG_D(TAG, " reloc YIELD"); + furi_delay_tick(1); + } + + if(storage_file_read(elf->fd, &rel, sizeof(Elf32_Rel)) != sizeof(Elf32_Rel)) { + FURI_LOG_E(TAG, " reloc read fail"); + string_clear(symbol_name); + return false; + } + + Elf32_Addr symAddr; + + int symEntry = ELF32_R_SYM(rel.r_info); + int relType = ELF32_R_TYPE(rel.r_info); + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + rel.r_offset; + + if(!address_cache_get(elf->relocation_cache, symEntry, &symAddr)) { + Elf32_Sym sym; + string_reset(symbol_name); + if(!elf_read_symbol(elf, symEntry, &sym, symbol_name)) { + FURI_LOG_E(TAG, " symbol read fail"); + string_clear(symbol_name); + return false; + } + + FURI_LOG_D( + TAG, + " %08X %08X %-16s %s", + (unsigned int)rel.r_offset, + (unsigned int)rel.r_info, + elf_reloc_type_to_str(relType), + string_get_cstr(symbol_name)); + + symAddr = elf_address_of(elf, &sym, string_get_cstr(symbol_name)); + address_cache_put(elf->relocation_cache, symEntry, symAddr); + } + + if(symAddr != ELF_INVALID_ADDRESS) { + FURI_LOG_D( + TAG, + " symAddr=%08X relAddr=%08X", + (unsigned int)symAddr, + (unsigned int)relAddr); + if(!elf_relocate_symbol(elf, relAddr, relType, symAddr)) { + relocate_result = false; + } + } else { + FURI_LOG_E(TAG, " No symbol address of %s", string_get_cstr(symbol_name)); + relocate_result = false; + } + } + string_clear(symbol_name); + + return relocate_result; + } else { + FURI_LOG_D(TAG, "Section not loaded"); + } + + return false; +} + +/**************************************************************************************************/ +/********************************************* MISC ***********************************************/ +/**************************************************************************************************/ + +static bool cstr_prefix(const char* prefix, const char* string) { + return strncmp(prefix, string, strlen(prefix)) == 0; +} + +/**************************************************************************************************/ +/************************************ Internal FAP interfaces *************************************/ +/**************************************************************************************************/ +typedef enum { + SectionTypeERROR = 0, + SectionTypeUnused = 1 << 0, + SectionTypeData = 1 << 1, + SectionTypeRelData = 1 << 2, + SectionTypeSymTab = 1 << 3, + SectionTypeStrTab = 1 << 4, + SectionTypeManifest = 1 << 5, + SectionTypeDebugLink = 1 << 6, + + SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab | SectionTypeManifest, +} SectionType; + +static bool elf_load_metadata( + ELFFile* elf, + Elf32_Shdr* section_header, + FlipperApplicationManifest* manifest) { + if(section_header->sh_size < sizeof(FlipperApplicationManifest)) { + return false; + } + + if(manifest == NULL) { + return true; + } + + return storage_file_seek(elf->fd, section_header->sh_offset, true) && + storage_file_read(elf->fd, manifest, section_header->sh_size) == + section_header->sh_size; +} + +static bool elf_load_debug_link(ELFFile* elf, Elf32_Shdr* section_header) { + elf->debug_link_info.debug_link_size = section_header->sh_size; + elf->debug_link_info.debug_link = malloc(section_header->sh_size); + + return storage_file_seek(elf->fd, section_header->sh_offset, true) && + storage_file_read(elf->fd, elf->debug_link_info.debug_link, section_header->sh_size) == + section_header->sh_size; +} + +static SectionType elf_preload_section( + ELFFile* elf, + size_t section_idx, + Elf32_Shdr* section_header, + string_t name_string, + FlipperApplicationManifest* manifest) { + const char* name = string_get_cstr(name_string); + + const struct { + const char* prefix; + SectionType type; + } lookup_sections[] = { + {".text", SectionTypeData}, + {".rodata", SectionTypeData}, + {".data", SectionTypeData}, + {".bss", SectionTypeData}, + {".preinit_array", SectionTypeData}, + {".init_array", SectionTypeData}, + {".fini_array", SectionTypeData}, + {".rel.text", SectionTypeRelData}, + {".rel.rodata", SectionTypeRelData}, + {".rel.data", SectionTypeRelData}, + {".rel.preinit_array", SectionTypeRelData}, + {".rel.init_array", SectionTypeRelData}, + {".rel.fini_array", SectionTypeRelData}, + }; + + for(size_t i = 0; i < COUNT_OF(lookup_sections); i++) { + if(cstr_prefix(lookup_sections[i].prefix, name)) { + FURI_LOG_D(TAG, "Found section %s", lookup_sections[i].prefix); + + if(lookup_sections[i].type == SectionTypeRelData) { + name = name + strlen(".rel"); + } + + ELFSection* section_p = elf_file_get_section(elf, name); + if(!section_p) { + ELFSection section = { + .data = NULL, + .sec_idx = 0, + .rel_sec_idx = 0, + .size = 0, + }; + + elf_file_put_section(elf, name, §ion); + section_p = elf_file_get_section(elf, name); + } + + if(lookup_sections[i].type == SectionTypeRelData) { + section_p->rel_sec_idx = section_idx; + } else { + section_p->sec_idx = section_idx; + } + + return lookup_sections[i].type; + } + } + + if(strcmp(name, ".symtab") == 0) { + FURI_LOG_D(TAG, "Found .symtab section"); + elf->symbol_table = section_header->sh_offset; + elf->symbol_count = section_header->sh_size / sizeof(Elf32_Sym); + return SectionTypeSymTab; + } else if(strcmp(name, ".strtab") == 0) { + FURI_LOG_D(TAG, "Found .strtab section"); + elf->symbol_table_strings = section_header->sh_offset; + return SectionTypeStrTab; + } else if(strcmp(name, ".fapmeta") == 0) { + FURI_LOG_D(TAG, "Found .fapmeta section"); + if(elf_load_metadata(elf, section_header, manifest)) { + return SectionTypeManifest; + } else { + return SectionTypeERROR; + } + } else if(strcmp(name, ".gnu_debuglink") == 0) { + FURI_LOG_D(TAG, "Found .gnu_debuglink section"); + if(elf_load_debug_link(elf, section_header)) { + return SectionTypeDebugLink; + } else { + return SectionTypeERROR; + } + } + + return SectionTypeUnused; +} + +static bool elf_load_section_data(ELFFile* elf, ELFSection* section) { + Elf32_Shdr section_header; + if(section->sec_idx == 0) { + FURI_LOG_D(TAG, "Section is not present"); + return true; + } + + if(!elf_read_section_header(elf, section->sec_idx, §ion_header)) { + return false; + } + + if(section_header.sh_size == 0) { + FURI_LOG_D(TAG, "No data for section"); + return true; + } + + section->data = aligned_malloc(section_header.sh_size, section_header.sh_addralign); + section->size = section_header.sh_size; + + if(section_header.sh_type == SHT_NOBITS) { + /* section is empty (.bss?) */ + /* no need to memset - allocator already did that */ + return true; + } + + if((!storage_file_seek(elf->fd, section_header.sh_offset, true)) || + (storage_file_read(elf->fd, section->data, section_header.sh_size) != + section_header.sh_size)) { + FURI_LOG_E(TAG, " seek/read fail"); + return false; + } + + FURI_LOG_D(TAG, "0x%X", section->data); + return true; +} + +static bool elf_relocate_section(ELFFile* elf, ELFSection* section) { + Elf32_Shdr section_header; + if(section->rel_sec_idx) { + FURI_LOG_D(TAG, "Relocating section"); + if(elf_read_section_header(elf, section->rel_sec_idx, §ion_header)) + return elf_relocate(elf, §ion_header, section); + else { + FURI_LOG_E(TAG, "Error reading section header"); + return false; + } + } else { + FURI_LOG_D(TAG, "No relocation index"); /* Not an error */ + } + return true; +} + +static void elf_file_call_section_list(ELFFile* elf, const char* name, bool reverse_order) { + ELFSection* section = elf_file_get_section(elf, name); + + if(section && section->size) { + const uint32_t* start = section->data; + const uint32_t* end = section->data + section->size; + + if(reverse_order) { + while(end > start) { + end--; + ((void (*)(void))(*end))(); + } + } else { + while(start < end) { + ((void (*)(void))(*start))(); + start++; + } + } + } +} + +/**************************************************************************************************/ +/********************************************* Public *********************************************/ +/**************************************************************************************************/ + +ELFFile* elf_file_alloc(Storage* storage, const ElfApiInterface* api_interface) { + ELFFile* elf = malloc(sizeof(ELFFile)); + elf->fd = storage_file_alloc(storage); + elf->api_interface = api_interface; + ELFSectionDict_init(elf->sections); + AddressCache_init(elf->trampoline_cache); + return elf; +} + +void elf_file_free(ELFFile* elf) { + // free sections data + { + ELFSectionDict_it_t it; + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); + ELFSectionDict_next(it)) { + const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it); + if(itref->value.data) { + aligned_free(itref->value.data); + } + free((void*)itref->key); + } + + ELFSectionDict_clear(elf->sections); + } + + // free trampoline data + { + AddressCache_it_t it; + for(AddressCache_it(it, elf->trampoline_cache); !AddressCache_end_p(it); + AddressCache_next(it)) { + const AddressCache_itref_t* itref = AddressCache_cref(it); + free((void*)itref->value); + } + + AddressCache_clear(elf->trampoline_cache); + } + + if(elf->debug_link_info.debug_link) { + free(elf->debug_link_info.debug_link); + } + + storage_file_free(elf->fd); + free(elf); +} + +bool elf_file_open(ELFFile* elf, const char* path) { + Elf32_Ehdr h; + Elf32_Shdr sH; + + if(!storage_file_open(elf->fd, path, FSAM_READ, FSOM_OPEN_EXISTING) || + !storage_file_seek(elf->fd, 0, true) || + storage_file_read(elf->fd, &h, sizeof(h)) != sizeof(h) || + !storage_file_seek(elf->fd, h.e_shoff + h.e_shstrndx * sizeof(sH), true) || + storage_file_read(elf->fd, &sH, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) { + return false; + } + + elf->entry = h.e_entry; + elf->sections_count = h.e_shnum; + elf->section_table = h.e_shoff; + elf->section_table_strings = sH.sh_offset; + return true; +} + +bool elf_file_load_manifest(ELFFile* elf, FlipperApplicationManifest* manifest) { + bool result = false; + string_t name; + string_init(name); + + FURI_LOG_D(TAG, "Looking for manifest section"); + for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) { + Elf32_Shdr section_header; + + string_reset(name); + if(!elf_read_section(elf, section_idx, §ion_header, name)) { + break; + } + + if(string_cmp(name, ".fapmeta") == 0) { + if(elf_load_metadata(elf, §ion_header, manifest)) { + FURI_LOG_D(TAG, "Load manifest done"); + result = true; + break; + } else { + break; + } + } + } + + string_clear(name); + return result; +} + +bool elf_file_load_section_table(ELFFile* elf, FlipperApplicationManifest* manifest) { + SectionType loaded_sections = SectionTypeERROR; + string_t name; + string_init(name); + + FURI_LOG_D(TAG, "Scan ELF indexs..."); + for(size_t section_idx = 1; section_idx < elf->sections_count; section_idx++) { + Elf32_Shdr section_header; + + string_reset(name); + if(!elf_read_section(elf, section_idx, §ion_header, name)) { + loaded_sections = SectionTypeERROR; + break; + } + + FURI_LOG_D(TAG, "Preloading data for section #%d %s", section_idx, string_get_cstr(name)); + SectionType section_type = + elf_preload_section(elf, section_idx, §ion_header, name, manifest); + loaded_sections |= section_type; + + if(section_type == SectionTypeERROR) { + loaded_sections = SectionTypeERROR; + break; + } + } + + string_clear(name); + FURI_LOG_D(TAG, "Load symbols done"); + + return IS_FLAGS_SET(loaded_sections, SectionTypeValid); +} + +ELFFileLoadStatus elf_file_load_sections(ELFFile* elf) { + ELFFileLoadStatus status = ELFFileLoadStatusSuccess; + ELFSectionDict_it_t it; + + AddressCache_init(elf->relocation_cache); + size_t start = furi_get_tick(); + + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { + ELFSectionDict_itref_t* itref = ELFSectionDict_ref(it); + FURI_LOG_D(TAG, "Loading section '%s'", itref->key); + if(!elf_load_section_data(elf, &itref->value)) { + FURI_LOG_E(TAG, "Error loading section '%s'", itref->key); + status = ELFFileLoadStatusUnspecifiedError; + } + } + + if(status == ELFFileLoadStatusSuccess) { + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); + ELFSectionDict_next(it)) { + ELFSectionDict_itref_t* itref = ELFSectionDict_ref(it); + FURI_LOG_D(TAG, "Relocating section '%s'", itref->key); + if(!elf_relocate_section(elf, &itref->value)) { + FURI_LOG_E(TAG, "Error relocating section '%s'", itref->key); + status = ELFFileLoadStatusMissingImports; + } + } + } + + /* Fixing up entry point */ + if(status == ELFFileLoadStatusSuccess) { + ELFSection* text_section = elf_file_get_section(elf, ".text"); + + if(text_section == NULL) { + FURI_LOG_E(TAG, "No .text section found"); + status = ELFFileLoadStatusUnspecifiedError; + } else { + elf->entry += (uint32_t)text_section->data; + } + } + + FURI_LOG_D(TAG, "Relocation cache size: %u", AddressCache_size(elf->relocation_cache)); + FURI_LOG_D(TAG, "Trampoline cache size: %u", AddressCache_size(elf->trampoline_cache)); + AddressCache_clear(elf->relocation_cache); + FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); + + return status; +} + +void elf_file_pre_run(ELFFile* elf) { + elf_file_call_section_list(elf, ".preinit_array", false); + elf_file_call_section_list(elf, ".init_array", false); +} + +int32_t elf_file_run(ELFFile* elf, void* args) { + int32_t result; + result = ((int32_t(*)(void*))elf->entry)(args); + return result; +} + +void elf_file_post_run(ELFFile* elf) { + elf_file_call_section_list(elf, ".fini_array", true); +} + +const ElfApiInterface* elf_file_get_api_interface(ELFFile* elf_file) { + return elf_file->api_interface; +} + +void elf_file_init_debug_info(ELFFile* elf, ELFDebugInfo* debug_info) { + // set entry + debug_info->entry = elf->entry; + + // copy debug info + memcpy(&debug_info->debug_link_info, &elf->debug_link_info, sizeof(ELFDebugLinkInfo)); + + // init mmap + debug_info->mmap_entry_count = ELFSectionDict_size(elf->sections); + debug_info->mmap_entries = malloc(sizeof(ELFMemoryMapEntry) * debug_info->mmap_entry_count); + uint32_t mmap_entry_idx = 0; + + ELFSectionDict_it_t it; + for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it); ELFSectionDict_next(it)) { + const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it); + + const void* data_ptr = itref->value.data; + if(data_ptr) { + debug_info->mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr; + debug_info->mmap_entries[mmap_entry_idx].name = itref->key; + mmap_entry_idx++; + } + } +} + +void elf_file_clear_debug_info(ELFDebugInfo* debug_info) { + // clear debug info + memset(&debug_info->debug_link_info, 0, sizeof(ELFDebugLinkInfo)); + + // clear mmap + if(debug_info->mmap_entries) { + free(debug_info->mmap_entries); + debug_info->mmap_entries = NULL; + } + + debug_info->mmap_entry_count = 0; +} diff --git a/lib/flipper_application/elf/elf_file.h b/lib/flipper_application/elf/elf_file.h new file mode 100644 index 000000000..673f165cc --- /dev/null +++ b/lib/flipper_application/elf/elf_file.h @@ -0,0 +1,127 @@ +/** + * @file elf_file.h + * ELF file loader + */ +#pragma once +#include +#include "../application_manifest.h" +#include "elf_api_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ELFFile ELFFile; + +typedef struct { + const char* name; + uint32_t address; +} ELFMemoryMapEntry; + +typedef struct { + uint32_t debug_link_size; + uint8_t* debug_link; +} ELFDebugLinkInfo; + +typedef struct { + uint32_t mmap_entry_count; + ELFMemoryMapEntry* mmap_entries; + ELFDebugLinkInfo debug_link_info; + off_t entry; +} ELFDebugInfo; + +typedef enum { + ELFFileLoadStatusSuccess = 0, + ELFFileLoadStatusUnspecifiedError, + ELFFileLoadStatusNoFreeMemory, + ELFFileLoadStatusMissingImports, +} ELFFileLoadStatus; + +/** + * @brief Allocate ELFFile instance + * @param storage + * @param api_interface + * @return ELFFile* + */ +ELFFile* elf_file_alloc(Storage* storage, const ElfApiInterface* api_interface); + +/** + * @brief Free ELFFile instance + * @param elf_file + */ +void elf_file_free(ELFFile* elf_file); + +/** + * @brief Open ELF file + * @param elf_file + * @param path + * @return bool + */ +bool elf_file_open(ELFFile* elf_file, const char* path); + +/** + * @brief Load ELF file manifest + * @param elf + * @param manifest + * @return bool + */ +bool elf_file_load_manifest(ELFFile* elf, FlipperApplicationManifest* manifest); + +/** + * @brief Load ELF file section table (load stage #1) + * @param elf_file + * @param manifest + * @return bool + */ +bool elf_file_load_section_table(ELFFile* elf_file, FlipperApplicationManifest* manifest); + +/** + * @brief Load and relocate ELF file sections (load stage #2) + * @param elf_file + * @return ELFFileLoadStatus + */ +ELFFileLoadStatus elf_file_load_sections(ELFFile* elf_file); + +/** + * @brief Execute ELF file pre-run stage, call static constructors for example (load stage #3) + * @param elf + */ +void elf_file_pre_run(ELFFile* elf); + +/** + * @brief Run ELF file (load stage #4) + * @param elf_file + * @param args + * @return int32_t + */ +int32_t elf_file_run(ELFFile* elf_file, void* args); + +/** + * @brief Execute ELF file post-run stage, call static destructors for example (load stage #5) + * @param elf + */ +void elf_file_post_run(ELFFile* elf); + +/** + * @brief Get ELF file API interface + * @param elf_file + * @return const ElfApiInterface* + */ +const ElfApiInterface* elf_file_get_api_interface(ELFFile* elf_file); + +/** + * @brief Get ELF file debug info + * @param elf_file + * @param debug_info + */ +void elf_file_init_debug_info(ELFFile* elf_file, ELFDebugInfo* debug_info); + +/** + * @brief Clear ELF file debug info generated by elf_file_init_debug_info + * @param debug_info + */ +void elf_file_clear_debug_info(ELFDebugInfo* debug_info); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_application/elf/elf_file_i.h b/lib/flipper_application/elf/elf_file_i.h new file mode 100644 index 000000000..1df075f06 --- /dev/null +++ b/lib/flipper_application/elf/elf_file_i.h @@ -0,0 +1,46 @@ +#pragma once +#include "elf_file.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +DICT_DEF2(AddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST) + +/** + * Callable elf entry type + */ +typedef int32_t(entry_t)(void*); + +typedef struct { + void* data; + uint16_t sec_idx; + uint16_t rel_sec_idx; + Elf32_Word size; +} ELFSection; + +DICT_DEF2(ELFSectionDict, const char*, M_CSTR_OPLIST, ELFSection, M_POD_OPLIST) + +struct ELFFile { + size_t sections_count; + off_t section_table; + off_t section_table_strings; + + size_t symbol_count; + off_t symbol_table; + off_t symbol_table_strings; + off_t entry; + ELFSectionDict_t sections; + + AddressCache_t relocation_cache; + AddressCache_t trampoline_cache; + + File* fd; + const ElfApiInterface* api_interface; + ELFDebugLinkInfo debug_link_info; +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/flipper_application/flipper_applicaiton_i.c b/lib/flipper_application/flipper_applicaiton_i.c deleted file mode 100644 index a2a069eeb..000000000 --- a/lib/flipper_application/flipper_applicaiton_i.c +++ /dev/null @@ -1,477 +0,0 @@ -#include "flipper_application_i.h" -#include - -#define TAG "fapp-i" - -#define RESOLVER_THREAD_YIELD_STEP 30 - -#define IS_FLAGS_SET(v, m) ((v & m) == m) -#define SECTION_OFFSET(e, n) (e->section_table + n * sizeof(Elf32_Shdr)) -#define SYMBOL_OFFSET(e, n) (e->_table + n * sizeof(Elf32_Shdr)) - -bool flipper_application_load_elf_headers(FlipperApplication* e, const char* path) { - Elf32_Ehdr h; - Elf32_Shdr sH; - - if(!storage_file_open(e->fd, path, FSAM_READ, FSOM_OPEN_EXISTING) || - !storage_file_seek(e->fd, 0, true) || - storage_file_read(e->fd, &h, sizeof(h)) != sizeof(h) || - !storage_file_seek(e->fd, h.e_shoff + h.e_shstrndx * sizeof(sH), true) || - storage_file_read(e->fd, &sH, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) { - return false; - } - - e->entry = h.e_entry; - e->sections = h.e_shnum; - e->section_table = h.e_shoff; - e->section_table_strings = sH.sh_offset; - return true; -} - -static bool flipper_application_load_metadata(FlipperApplication* e, Elf32_Shdr* sh) { - if(sh->sh_size < sizeof(e->manifest)) { - return false; - } - - return storage_file_seek(e->fd, sh->sh_offset, true) && - storage_file_read(e->fd, &e->manifest, sh->sh_size) == sh->sh_size; -} - -static bool flipper_application_load_debug_link(FlipperApplication* e, Elf32_Shdr* sh) { - e->state.debug_link_size = sh->sh_size; - e->state.debug_link = malloc(sh->sh_size); - - return storage_file_seek(e->fd, sh->sh_offset, true) && - storage_file_read(e->fd, e->state.debug_link, sh->sh_size) == sh->sh_size; -} - -static FindFlags_t flipper_application_preload_section( - FlipperApplication* e, - Elf32_Shdr* sh, - const char* name, - int n) { - FURI_LOG_D(TAG, "Processing: %s", name); - - const struct { - const char* name; - uint16_t* ptr_section_idx; - FindFlags_t flags; - } lookup_sections[] = { - {".text", &e->text.sec_idx, FoundText}, - {".rodata", &e->rodata.sec_idx, FoundRodata}, - {".data", &e->data.sec_idx, FoundData}, - {".bss", &e->bss.sec_idx, FoundBss}, - {".rel.text", &e->text.rel_sec_idx, FoundRelText}, - {".rel.rodata", &e->rodata.rel_sec_idx, FoundRelRodata}, - {".rel.data", &e->data.rel_sec_idx, FoundRelData}, - }; - - for(size_t i = 0; i < COUNT_OF(lookup_sections); i++) { - if(strcmp(name, lookup_sections[i].name) == 0) { - *lookup_sections[i].ptr_section_idx = n; - return lookup_sections[i].flags; - } - } - - if(strcmp(name, ".symtab") == 0) { - e->symbol_table = sh->sh_offset; - e->symbol_count = sh->sh_size / sizeof(Elf32_Sym); - return FoundSymTab; - } else if(strcmp(name, ".strtab") == 0) { - e->symbol_table_strings = sh->sh_offset; - return FoundStrTab; - } else if(strcmp(name, ".fapmeta") == 0) { - // Load metadata immediately - if(flipper_application_load_metadata(e, sh)) { - return FoundFappManifest; - } - } else if(strcmp(name, ".gnu_debuglink") == 0) { - if(flipper_application_load_debug_link(e, sh)) { - return FoundDebugLink; - } - } - return FoundERROR; -} - -static bool - read_string_from_offset(FlipperApplication* e, off_t offset, char* buffer, size_t buffer_size) { - bool success = false; - - off_t old = storage_file_tell(e->fd); - if(storage_file_seek(e->fd, offset, true) && - (storage_file_read(e->fd, buffer, buffer_size) == buffer_size)) { - success = true; - } - storage_file_seek(e->fd, old, true); - - return success; -} - -static bool read_section_name(FlipperApplication* e, off_t off, char* buf, size_t max) { - return read_string_from_offset(e, e->section_table_strings + off, buf, max); -} - -static bool read_symbol_name(FlipperApplication* e, off_t off, char* buf, size_t max) { - return read_string_from_offset(e, e->symbol_table_strings + off, buf, max); -} - -static bool read_section_header(FlipperApplication* e, int n, Elf32_Shdr* h) { - off_t offset = SECTION_OFFSET(e, n); - return storage_file_seek(e->fd, offset, true) && - storage_file_read(e->fd, h, sizeof(Elf32_Shdr)) == sizeof(Elf32_Shdr); -} - -static bool read_section(FlipperApplication* e, int n, Elf32_Shdr* h, char* name, size_t nlen) { - if(!read_section_header(e, n, h)) { - return false; - } - if(!h->sh_name) { - return true; - } - return read_section_name(e, h->sh_name, name, nlen); -} - -bool flipper_application_load_section_table(FlipperApplication* e) { - furi_check(e->state.mmap_entry_count == 0); - - size_t n; - FindFlags_t found = FoundERROR; - FURI_LOG_D(TAG, "Scan ELF indexs..."); - for(n = 1; n < e->sections; n++) { - Elf32_Shdr section_header; - char name[33] = {0}; - if(!read_section_header(e, n, §ion_header)) { - return false; - } - if(section_header.sh_name && - !read_section_name(e, section_header.sh_name, name, sizeof(name))) { - return false; - } - - FURI_LOG_T(TAG, "Examining section %d %s", n, name); - FindFlags_t section_flags = - flipper_application_preload_section(e, §ion_header, name, n); - found |= section_flags; - if((section_flags & FoundGdbSection) != 0) { - e->state.mmap_entry_count++; - } - if(IS_FLAGS_SET(found, FoundAll)) { - return true; - } - } - - FURI_LOG_D(TAG, "Load symbols done"); - return IS_FLAGS_SET(found, FoundValid); -} - -static const char* type_to_str(int symt) { -#define STRCASE(name) \ - case name: \ - return #name; - switch(symt) { - STRCASE(R_ARM_NONE) - STRCASE(R_ARM_ABS32) - STRCASE(R_ARM_THM_PC22) - STRCASE(R_ARM_THM_JUMP24) - default: - return "R_"; - } -#undef STRCASE -} - -static void relocate_jmp_call(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { - UNUSED(type); - uint16_t upper_insn = ((uint16_t*)relAddr)[0]; - uint16_t lower_insn = ((uint16_t*)relAddr)[1]; - uint32_t S = (upper_insn >> 10) & 1; - uint32_t J1 = (lower_insn >> 13) & 1; - uint32_t J2 = (lower_insn >> 11) & 1; - - int32_t offset = (S << 24) | /* S -> offset[24] */ - ((~(J1 ^ S) & 1) << 23) | /* J1 -> offset[23] */ - ((~(J2 ^ S) & 1) << 22) | /* J2 -> offset[22] */ - ((upper_insn & 0x03ff) << 12) | /* imm10 -> offset[12:21] */ - ((lower_insn & 0x07ff) << 1); /* imm11 -> offset[1:11] */ - if(offset & 0x01000000) offset -= 0x02000000; - - offset += symAddr - relAddr; - - S = (offset >> 24) & 1; - J1 = S ^ (~(offset >> 23) & 1); - J2 = S ^ (~(offset >> 22) & 1); - - upper_insn = ((upper_insn & 0xf800) | (S << 10) | ((offset >> 12) & 0x03ff)); - ((uint16_t*)relAddr)[0] = upper_insn; - - lower_insn = ((lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | ((offset >> 1) & 0x07ff)); - ((uint16_t*)relAddr)[1] = lower_insn; -} - -static bool relocate_symbol(Elf32_Addr relAddr, int type, Elf32_Addr symAddr) { - switch(type) { - case R_ARM_ABS32: - *((uint32_t*)relAddr) += symAddr; - FURI_LOG_D(TAG, " R_ARM_ABS32 relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); - break; - case R_ARM_THM_PC22: - case R_ARM_THM_JUMP24: - relocate_jmp_call(relAddr, type, symAddr); - FURI_LOG_D( - TAG, " R_ARM_THM_CALL/JMP relocated is 0x%08X", (unsigned int)*((uint32_t*)relAddr)); - break; - default: - FURI_LOG_D(TAG, " Undefined relocation %d", type); - return false; - } - return true; -} - -static ELFSection_t* section_of(FlipperApplication* e, int index) { - if(e->text.sec_idx == index) { - return &e->text; - } else if(e->data.sec_idx == index) { - return &e->data; - } else if(e->bss.sec_idx == index) { - return &e->bss; - } else if(e->rodata.sec_idx == index) { - return &e->rodata; - } - return NULL; -} - -static Elf32_Addr address_of(FlipperApplication* e, Elf32_Sym* sym, const char* sName) { - if(sym->st_shndx == SHN_UNDEF) { - Elf32_Addr addr = 0; - if(e->api_interface->resolver_callback(sName, &addr)) { - return addr; - } - } else { - ELFSection_t* symSec = section_of(e, sym->st_shndx); - if(symSec) { - return ((Elf32_Addr)symSec->data) + sym->st_value; - } - } - FURI_LOG_D(TAG, " Can not find address for symbol %s", sName); - return ELF_INVALID_ADDRESS; -} - -static bool read_symbol(FlipperApplication* e, int n, Elf32_Sym* sym, char* name, size_t nlen) { - bool success = false; - off_t old = storage_file_tell(e->fd); - off_t pos = e->symbol_table + n * sizeof(Elf32_Sym); - if(storage_file_seek(e->fd, pos, true) && - storage_file_read(e->fd, sym, sizeof(Elf32_Sym)) == sizeof(Elf32_Sym)) { - if(sym->st_name) - success = read_symbol_name(e, sym->st_name, name, nlen); - else { - Elf32_Shdr shdr; - success = read_section(e, sym->st_shndx, &shdr, name, nlen); - } - } - storage_file_seek(e->fd, old, true); - return success; -} - -static bool - relocation_cache_get(RelocationAddressCache_t cache, int symEntry, Elf32_Addr* symAddr) { - Elf32_Addr* addr = RelocationAddressCache_get(cache, symEntry); - if(addr) { - *symAddr = *addr; - return true; - } else { - return false; - } -} - -static void - relocation_cache_put(RelocationAddressCache_t cache, int symEntry, Elf32_Addr symAddr) { - RelocationAddressCache_set_at(cache, symEntry, symAddr); -} - -#define MAX_SYMBOL_NAME_LEN 128u - -static bool relocate(FlipperApplication* e, Elf32_Shdr* h, ELFSection_t* s) { - if(s->data) { - Elf32_Rel rel; - size_t relEntries = h->sh_size / sizeof(rel); - size_t relCount; - (void)storage_file_seek(e->fd, h->sh_offset, true); - FURI_LOG_D(TAG, " Offset Info Type Name"); - - int relocate_result = true; - char symbol_name[MAX_SYMBOL_NAME_LEN + 1] = {0}; - - for(relCount = 0; relCount < relEntries; relCount++) { - if(relCount % RESOLVER_THREAD_YIELD_STEP == 0) { - FURI_LOG_D(TAG, " reloc YIELD"); - furi_delay_tick(1); - } - - if(storage_file_read(e->fd, &rel, sizeof(Elf32_Rel)) != sizeof(Elf32_Rel)) { - FURI_LOG_E(TAG, " reloc read fail"); - return false; - } - - Elf32_Addr symAddr; - - int symEntry = ELF32_R_SYM(rel.r_info); - int relType = ELF32_R_TYPE(rel.r_info); - Elf32_Addr relAddr = ((Elf32_Addr)s->data) + rel.r_offset; - - if(!relocation_cache_get(e->relocation_cache, symEntry, &symAddr)) { - Elf32_Sym sym; - if(!read_symbol(e, symEntry, &sym, symbol_name, MAX_SYMBOL_NAME_LEN)) { - FURI_LOG_E(TAG, " symbol read fail"); - return false; - } - - FURI_LOG_D( - TAG, - " %08X %08X %-16s %s", - (unsigned int)rel.r_offset, - (unsigned int)rel.r_info, - type_to_str(relType), - symbol_name); - - symAddr = address_of(e, &sym, symbol_name); - relocation_cache_put(e->relocation_cache, symEntry, symAddr); - } - - if(symAddr != ELF_INVALID_ADDRESS) { - FURI_LOG_D( - TAG, - " symAddr=%08X relAddr=%08X", - (unsigned int)symAddr, - (unsigned int)relAddr); - if(!relocate_symbol(relAddr, relType, symAddr)) { - relocate_result = false; - } - } else { - FURI_LOG_D(TAG, " No symbol address of %s", symbol_name); - relocate_result = false; - } - } - - return relocate_result; - } else - FURI_LOG_I(TAG, "Section not loaded"); - - return false; -} - -static bool flipper_application_load_section_data(FlipperApplication* e, ELFSection_t* s) { - Elf32_Shdr section_header; - if(s->sec_idx == 0) { - FURI_LOG_I(TAG, "Section is not present"); - return true; - } - - if(!read_section_header(e, s->sec_idx, §ion_header)) { - return false; - } - - if(section_header.sh_size == 0) { - FURI_LOG_I(TAG, "No data for section"); - return true; - } - - s->data = aligned_malloc(section_header.sh_size, section_header.sh_addralign); - // e->state.mmap_entry_count++; - - if(section_header.sh_type == SHT_NOBITS) { - /* section is empty (.bss?) */ - /* no need to memset - allocator already did that */ - /* memset(s->data, 0, h->sh_size); */ - FURI_LOG_D(TAG, "0x%X", s->data); - return true; - } - - if((!storage_file_seek(e->fd, section_header.sh_offset, true)) || - (storage_file_read(e->fd, s->data, section_header.sh_size) != section_header.sh_size)) { - FURI_LOG_E(TAG, " seek/read fail"); - flipper_application_free_section(s); - return false; - } - - FURI_LOG_D(TAG, "0x%X", s->data); - return true; -} - -static bool flipper_application_relocate_section(FlipperApplication* e, ELFSection_t* s) { - Elf32_Shdr section_header; - if(s->rel_sec_idx) { - FURI_LOG_D(TAG, "Relocating section"); - if(read_section_header(e, s->rel_sec_idx, §ion_header)) - return relocate(e, §ion_header, s); - else { - FURI_LOG_E(TAG, "Error reading section header"); - return false; - } - } else - FURI_LOG_D(TAG, "No relocation index"); /* Not an error */ - return true; -} - -FlipperApplicationLoadStatus flipper_application_load_sections(FlipperApplication* e) { - FlipperApplicationLoadStatus status = FlipperApplicationLoadStatusSuccess; - RelocationAddressCache_init(e->relocation_cache); - size_t start = furi_get_tick(); - - struct { - ELFSection_t* section; - const char* name; - } sections[] = { - {&e->text, ".text"}, - {&e->rodata, ".rodata"}, - {&e->data, ".data"}, - {&e->bss, ".bss"}, - }; - - for(size_t i = 0; i < COUNT_OF(sections); i++) { - if(!flipper_application_load_section_data(e, sections[i].section)) { - FURI_LOG_E(TAG, "Error loading section '%s'", sections[i].name); - status = FlipperApplicationLoadStatusUnspecifiedError; - } - } - - if(status == FlipperApplicationLoadStatusSuccess) { - for(size_t i = 0; i < COUNT_OF(sections); i++) { - if(!flipper_application_relocate_section(e, sections[i].section)) { - FURI_LOG_E(TAG, "Error relocating section '%s'", sections[i].name); - status = FlipperApplicationLoadStatusMissingImports; - } - } - } - - if(status == FlipperApplicationLoadStatusSuccess) { - e->state.mmap_entries = - malloc(sizeof(FlipperApplicationMemoryMapEntry) * e->state.mmap_entry_count); - uint32_t mmap_entry_idx = 0; - for(size_t i = 0; i < COUNT_OF(sections); i++) { - const void* data_ptr = sections[i].section->data; - if(data_ptr) { - FURI_LOG_I(TAG, "0x%X %s", (uint32_t)data_ptr, sections[i].name); - e->state.mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr; - e->state.mmap_entries[mmap_entry_idx].name = sections[i].name; - mmap_entry_idx++; - } - } - furi_check(mmap_entry_idx == e->state.mmap_entry_count); - - /* Fixing up entry point */ - e->entry += (uint32_t)e->text.data; - } - - FURI_LOG_D(TAG, "Relocation cache size: %u", RelocationAddressCache_size(e->relocation_cache)); - RelocationAddressCache_clear(e->relocation_cache); - FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); - - return status; -} - -void flipper_application_free_section(ELFSection_t* s) { - if(s->data) { - aligned_free(s->data); - } - s->data = NULL; -} diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 6e84cce38..cf44eebb2 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -1,16 +1,22 @@ #include "flipper_application.h" -#include "flipper_application_i.h" +#include "elf/elf_file.h" #define TAG "fapp" +struct FlipperApplication { + ELFDebugInfo state; + FlipperApplicationManifest manifest; + ELFFile* elf; + FuriThread* thread; +}; + /* For debugger access to app state */ FlipperApplication* last_loaded_app = NULL; FlipperApplication* flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) { FlipperApplication* app = malloc(sizeof(FlipperApplication)); - app->api_interface = api_interface; - app->fd = storage_file_alloc(storage); + app->elf = elf_file_alloc(storage, api_interface); app->thread = NULL; return app; } @@ -25,56 +31,71 @@ void flipper_application_free(FlipperApplication* app) { last_loaded_app = NULL; - if(app->state.debug_link_size) { - free(app->state.debug_link); - } - - if(app->state.mmap_entries) { - free(app->state.mmap_entries); - } - - ELFSection_t* sections[] = {&app->text, &app->rodata, &app->data, &app->bss}; - for(size_t i = 0; i < COUNT_OF(sections); i++) { - flipper_application_free_section(sections[i]); - } - - storage_file_free(app->fd); - + elf_file_clear_debug_info(&app->state); + elf_file_free(app->elf); free(app); } -/* Parse headers, load manifest */ -FlipperApplicationPreloadStatus - flipper_application_preload(FlipperApplication* app, const char* path) { - if(!flipper_application_load_elf_headers(app, path) || - !flipper_application_load_section_table(app)) { - return FlipperApplicationPreloadStatusInvalidFile; - } - - if((app->manifest.base.manifest_magic != FAP_MANIFEST_MAGIC) && - (app->manifest.base.manifest_version == FAP_MANIFEST_SUPPORTED_VERSION)) { +static FlipperApplicationPreloadStatus + flipper_application_validate_manifest(FlipperApplication* app) { + if(!flipper_application_manifest_is_valid(&app->manifest)) { return FlipperApplicationPreloadStatusInvalidManifest; } - if(app->manifest.base.api_version.major != app->api_interface->api_version_major /* || - app->manifest.base.api_version.minor > app->api_interface->api_version_minor */) { + if(!flipper_application_manifest_is_compatible( + &app->manifest, elf_file_get_api_interface(app->elf))) { return FlipperApplicationPreloadStatusApiMismatch; } return FlipperApplicationPreloadStatusSuccess; } +/* Parse headers, load manifest */ +FlipperApplicationPreloadStatus + flipper_application_preload_manifest(FlipperApplication* app, const char* path) { + if(!elf_file_open(app->elf, path) || !elf_file_load_manifest(app->elf, &app->manifest)) { + return FlipperApplicationPreloadStatusInvalidFile; + } + + return flipper_application_validate_manifest(app); +} + +/* Parse headers, load full file */ +FlipperApplicationPreloadStatus + flipper_application_preload(FlipperApplication* app, const char* path) { + if(!elf_file_open(app->elf, path) || !elf_file_load_section_table(app->elf, &app->manifest)) { + return FlipperApplicationPreloadStatusInvalidFile; + } + + return flipper_application_validate_manifest(app); +} + const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app) { return &app->manifest; } FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) { last_loaded_app = app; - return flipper_application_load_sections(app); + ELFFileLoadStatus status = elf_file_load_sections(app->elf); + + switch(status) { + case ELFFileLoadStatusSuccess: + elf_file_init_debug_info(app->elf, &app->state); + return FlipperApplicationLoadStatusSuccess; + case ELFFileLoadStatusNoFreeMemory: + return FlipperApplicationLoadStatusNoFreeMemory; + case ELFFileLoadStatusMissingImports: + return FlipperApplicationLoadStatusMissingImports; + default: + return FlipperApplicationLoadStatusUnspecifiedError; + } } -const FlipperApplicationState* flipper_application_get_state(FlipperApplication* app) { - return &app->state; +static int32_t flipper_application_thread(void* context) { + elf_file_pre_run(last_loaded_app->elf); + int32_t result = elf_file_run(last_loaded_app->elf, context); + elf_file_post_run(last_loaded_app->elf); + return result; } FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { @@ -86,20 +107,12 @@ FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { app->thread = furi_thread_alloc(); furi_thread_set_stack_size(app->thread, manifest->stack_size); furi_thread_set_name(app->thread, manifest->name); - furi_thread_set_callback(app->thread, (entry_t*)app->entry); + furi_thread_set_callback(app->thread, flipper_application_thread); furi_thread_set_context(app->thread, args); return app->thread; } -FuriThread* flipper_application_get_thread(FlipperApplication* app) { - return app->thread; -} - -void const* flipper_application_get_entry_address(FlipperApplication* app) { - return (void*)app->entry; -} - static const char* preload_status_strings[] = { [FlipperApplicationPreloadStatusSuccess] = "Success", [FlipperApplicationPreloadStatusUnspecifiedError] = "Unknown error", diff --git a/lib/flipper_application/flipper_application.h b/lib/flipper_application/flipper_application.h index 34de40388..b3e5996bb 100644 --- a/lib/flipper_application/flipper_application.h +++ b/lib/flipper_application/flipper_application.h @@ -1,3 +1,7 @@ +/** + * @file flipper_application.h + * Flipper application + */ #pragma once #include "application_manifest.h" @@ -79,6 +83,14 @@ void flipper_application_free(FlipperApplication* app); FlipperApplicationPreloadStatus flipper_application_preload(FlipperApplication* app, const char* path); +/** + * @brief Validate elf file and load application manifest + * @param app Application pointer + * @return Preload result code + */ +FlipperApplicationPreloadStatus + flipper_application_preload_manifest(FlipperApplication* app, const char* path); + /** * @brief Get pointer to application manifest for preloaded application * @param app Application pointer @@ -93,13 +105,6 @@ const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplic */ FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app); -/** - * @brief Get state object for loaded application - * @param app Application pointer - * @return Pointer to state object - */ -const FlipperApplicationState* flipper_application_get_state(FlipperApplication* app); - /** * @brief Create application thread at entry point address, using app name and * stack size from metadata. Returned thread isn't started yet. @@ -110,20 +115,6 @@ const FlipperApplicationState* flipper_application_get_state(FlipperApplication* */ FuriThread* flipper_application_spawn(FlipperApplication* app, void* args); -/** - * @brief Get previously spawned thread - * @param app Application pointer - * @return Created thread - */ -FuriThread* flipper_application_get_thread(FlipperApplication* app); - -/** - * @brief Return relocated and valid address of app's entry point - * @param app Application pointer - * @return Address of app's entry point - */ -void const* flipper_application_get_entry_address(FlipperApplication* app); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/flipper_application/flipper_application_i.h b/lib/flipper_application/flipper_application_i.h deleted file mode 100644 index 8adf5c0d2..000000000 --- a/lib/flipper_application/flipper_application_i.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include "elf.h" -#include "flipper_application.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -DICT_DEF2(RelocationAddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST) - -/** - * Callable elf entry type - */ -typedef int32_t(entry_t)(void*); - -typedef struct { - void* data; - uint16_t sec_idx; - uint16_t rel_sec_idx; -} ELFSection_t; - -struct FlipperApplication { - const ElfApiInterface* api_interface; - File* fd; - FlipperApplicationState state; - FlipperApplicationManifest manifest; - - size_t sections; - off_t section_table; - off_t section_table_strings; - - size_t symbol_count; - off_t symbol_table; - off_t symbol_table_strings; - off_t entry; - - ELFSection_t text; - ELFSection_t rodata; - ELFSection_t data; - ELFSection_t bss; - - FuriThread* thread; - RelocationAddressCache_t relocation_cache; -}; - -typedef enum { - FoundERROR = 0, - FoundSymTab = (1 << 0), - FoundStrTab = (1 << 2), - FoundText = (1 << 3), - FoundRodata = (1 << 4), - FoundData = (1 << 5), - FoundBss = (1 << 6), - FoundRelText = (1 << 7), - FoundRelRodata = (1 << 8), - FoundRelData = (1 << 9), - FoundRelBss = (1 << 10), - FoundFappManifest = (1 << 11), - FoundDebugLink = (1 << 12), - FoundValid = FoundSymTab | FoundStrTab | FoundFappManifest, - FoundExec = FoundValid | FoundText, - FoundGdbSection = FoundText | FoundRodata | FoundData | FoundBss, - FoundAll = FoundSymTab | FoundStrTab | FoundText | FoundRodata | FoundData | FoundBss | - FoundRelText | FoundRelRodata | FoundRelData | FoundRelBss | FoundDebugLink, -} FindFlags_t; - -/** - * @brief Load and validate basic ELF file headers - * @param e Application instance - * @param path FS path to application file - * @return true if ELF file is valid - */ -bool flipper_application_load_elf_headers(FlipperApplication* e, const char* path); - -/** - * @brief Iterate over all sections and save related indexes - * @param e Application instance - * @return true if all required sections are found - */ -bool flipper_application_load_section_table(FlipperApplication* e); - -/** - * @brief Load section data to memory and process relocations - * @param e Application instance - * @return Status code - */ -FlipperApplicationLoadStatus flipper_application_load_sections(FlipperApplication* e); - -/** - * @brief Release section data - * @param s section pointer - */ -void flipper_application_free_section(ELFSection_t* s); - -#ifdef __cplusplus -} -#endif \ No newline at end of file From bc777b2eff816613c6a703e46ab5e24c7d694127 Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sun, 25 Sep 2022 18:34:52 +0400 Subject: [PATCH 2/3] SubGhz: fix config menu (#1748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SubGhz: fix config menu * SubGhz: fix gui Magellen protocol * SubGhz: fix gui Transmit SubGhz * SubGhz: keeloq, new gen manufacture code * SubGhz: Update keeloq_mfcodes Co-authored-by: あく --- .../scenes/subghz_scene_receiver_config.c | 1 + applications/main/subghz/views/transmitter.c | 7 +- assets/resources/subghz/assets/keeloq_mfcodes | 92 ++++++++++--------- lib/subghz/protocols/keeloq.c | 12 +++ lib/subghz/protocols/keeloq_common.c | 12 +++ lib/subghz/protocols/keeloq_common.h | 9 ++ lib/subghz/protocols/magellen.c | 2 +- 7 files changed, 87 insertions(+), 48 deletions(-) diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index c59630f7e..541ec0e0d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -223,6 +223,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even void subghz_scene_receiver_config_on_exit(void* context) { SubGhz* subghz = context; + variable_item_list_set_selected_item(subghz->variable_item_list, 0); variable_item_list_reset(subghz->variable_item_list); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 3cbcf098a..dd2b6d321 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -45,7 +45,7 @@ void subghz_view_transmitter_add_data_to_show( } static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { - const uint8_t button_height = 13; + const uint8_t button_height = 12; const uint8_t vertical_offset = 3; const uint8_t horizontal_offset = 1; const uint8_t string_width = canvas_string_width(canvas, str); @@ -69,7 +69,10 @@ static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str canvas_invert_color(canvas); canvas_draw_icon( - canvas, x + horizontal_offset, y - button_height + vertical_offset, &I_ButtonCenter_7x7); + canvas, + x + horizontal_offset, + y - button_height + vertical_offset - 1, + &I_ButtonCenter_7x7); canvas_draw_str( canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str); canvas_invert_color(canvas); diff --git a/assets/resources/subghz/assets/keeloq_mfcodes b/assets/resources/subghz/assets/keeloq_mfcodes index f9771285e..b8fc36903 100644 --- a/assets/resources/subghz/assets/keeloq_mfcodes +++ b/assets/resources/subghz/assets/keeloq_mfcodes @@ -1,48 +1,50 @@ Filetype: Flipper SubGhz Keystore File Version: 0 Encryption: 1 -IV: F2 D4 F5 5A B3 CC 3F 21 28 3A AF ED D1 EB 73 DF -BBFA4D79A73C384D6E07E717F761F32A625F28AA1DB2261B8B19A18261E30AB6 -CE4004AB56111B0B3D486770705FAD8BD616A80957EA2C537BAF1FD09E552DA3 -F974561612C9C751237C64D978F706B41873FDBE38851306574F436CB02D9ECA -E29CAB7C2C2D9853D0F4DF69F582562E8182234E78B355540F6FE3F78C73D518 -97ABE18993A700A607E37DC88E1434F84DDD1C2771693978C9D2FA4CE4F2AB7BBC7C3EB3E8545B37FBBE1C1F1CA03543 -E86ABD0AAE5A4B4A9414C9CB6112CA49B3A8EC29723B14DCA85902F41B05ADDC -C1FBE921035F408C59DA6AD5E76E3887AC9BC90146619B3CAE445BED556E96AC -232C9F86915B927888352797B45F159268FE78956CF09B8D241CDC393D3B0225 -3D9E2A3C701C9D4DD4D72038D4536CA6F515C547CAB0AD18BA71204BD2ABFB74 -4D69A4506D2C97EF8EC68F90CF1AD1065A1EB909793EEB3AF71B0D75E55B9E76 -5A7F4595DFA181C3E946EBEE4974DBD6DA85AF6FCAD0B3725FDD28667175A421D69A2122853E57927C38CCF368732476 -6A946FAEDE134155B5A88EC01AA535E7A778947D360218B560381A64CAF9ACE896079D04C14718D5AD5C0D4EE3005F52 -88AC0C723AAA875A1885C8392A616FA43B205119B0E8D299193979A1921FC8B3 -40588AADA5E1A8BE214B2CCF32D268B48C6B783AE0DD10D88BDF3FF88E921E09 -A7BE05D05DEC9B9A3AE1575D411BF7B12366AD78B726F3E3E843E7BF199961A4 -79F973A155A4367F0EAA078AA0857A2A2A82FC4C8A5AE9E567E7CBF62C2A5CE2 -C38296EEABDA1F95D0C401CC6DDC8656476DC19248588EEF1CB93773D94CDB02A40C902970C4FCB14FABEFFB4F8BC208 -B0B7699B3C3573EE4D88D8CE65FAF3532B5A741D1F20892C0F38BAA2BCE98F2D -6E401D6BDB1B33A404DEB668F3FB353166475487BAADE4A348E3CFDEB3B1B54B -0E44B87878617559783CC6A7C65BE9F99950FE8956ED4BB04894BC53085E3A09CA19915B1E8C143A68D1B7A97F5D1ECB -AC19E55638429C65E6E567C0E96DA9648F8FB80215CF693D7FD5DD86FE7989AC7AC7BAE86BBD4FFF7161AFFB405FFA98 -BCE70C69D90AD639A737813FC8FD26F40F803137BD36E47651C266A671428D6F -F053CF5255AD2E1875A5C38635F7BF203B1DAE1433B162C30AE8695AC8A5589D -B7EFC77FFA98B173E429B3566A27842C4DC5E91B0BC01F07A6A98332C4E1F42A -D7C7950FFB2C5E7D9BCDBC230BF5F1BFFC0FE6F1CF5C8C6013DD90E41AE403FE -50667B2E5909FD5F9D6385788A81DE5F72E56512EAD6BF5EACCA959CB6AF0DEF -6435E07E5E952124B0F80F76E0F68265B8289087387E35C6D51831B299335480 -D7DE1F7748FB8BF90561151CC6AEADC160CA883FE5228768A3737A89F358AF58 -FA206F860C6F981FD4A358FDEA5E1860353406D8416FF2A811D17EBA09C803EA -F2F7B2C6705D1457315F2AAA859AB53592241D63B84C045BC742D220BA110144 -3F0E05E572D1DF5E2B0BBB20EF8F3EB4D198CDF2794F86089E1DB0EF975E9337 -7D54D088C22AA3BA9A97FAB64371B8D512CDEC2A4355116BE2B74BCEC7FEC852 -0FD951F13E19F0FC1A25655DA430640034BE34659C526238E62B6042691998CB -FCA04B0BF98FA89AAEF41A78AE7141EF7783E0D0CBAAB1B6F00C0AD3EAA84A54759D46E1A9BEEDCCE68BA12902802111 -6AD801CE08D58A380B689574BD7FCACC5DF768BDD93AD7EE1AA514A2351EF13A -0A820F47699AFC4A5E3285BF521771FC5B6C5FB7C6C08A1990DA3B3A6766E860 -A7AAC90972DB24D20B57DDD46DC2624FC6169D529426E64B0544AC383799BB2A -AF6088873BC71ED672FA39D50B386523825218C43CDB35D691B0C5895B7EF5C2 -774DFAC8D285241368CB377DA947D7A94951A1520017DF77FE2E6A517D5C6A1FC768BB1E2398F5AF71B10D1806C04CCD -AA788A707E64C40E2A0EB8154FE795EAC68B936FD6BAC5DEF7677A4D5FE344DD -A193EF5D1B223B0FA3C231052EDBDD7A31B0C192BCD8E7E37E11D4D899476ACD -F6986E08949122D46BFA7F218B089E8DB00DCFA6971C5F2468CDDD179E5BBC40 -EDC23A07689EF6229081D1AB9E249E68527BD33EB72C242BA97727E64AF15BCC -70CC64359A2A5DE40D5A30E916DE6532BCC511E7489CD3A2E5DEC269D303FDBD83B7EA14BF13B40E3C960C6D3D12774B +IV: 2A 34 F1 5A AF 6F F5 1A 83 A6 1E DA DE B7 3D F1 +06B63DF24AE073A2F2B19C55CA9E8364FBECD26E49C551990153F6513BDE5267 +6139C78C74C341EB7474085CF1D047BD6FB005F80A72AF3EF3F89D58EF5DF500 +D85F11689020ECA47FBE9C2B67EE41A81E1F06DE2A35AF958965E3ECE29EA701 +1AE9073A42FE0E439544FE6945F6B33CF15A7A4A279020B5E0B3BE33FD189A7E +E161F007854BB33E0056FA09A2E2DEE66789B5C87C8D6D3DE2C8C1BD2B48983EB9D1C5697CA6E95996918F7C47B761B0 +59AE4644DCB3D720C38B5115F230DA58E7BE0A697907F6174BB05AB7886ACDB1 +634DF0BCC185C4C1F7E1B1594B4438D051ABAE092433078963063B51D961D08C +1EBEBCB49E498B9BE977D53EC21B9A546155B627737BD0AA832D496035729346 +4DFA93E639197772D57E8ACE04512CEFC045B8CC965C175A25ED525B630CBB63 +C2D5235D1014A319B249EAE8A5EE350F18D5AB8A498EF222704BD4EB1435F388 +F66D1937160E1392197F463A52E87FCE938A92070892113443C348D7553327A5715CF615CE2F2C96284F47759E043419 +841D29E7CBE040188E2283BFBA9F26EF2F65CCB085B56C3515E8C46C3F20BD75BAA963550869435FDAF509CEEE66A2C4 +7D87E24487D307635E7A17B989B8547EE11F3BF3468D055F0B44633B631BA42C +B4916043973501B95A82B329196D6EBA69FBBC3AF8FD914583104E0E18CE82F6 +E4649F9C2A5465D2EA6F3E9724DD06CD6962FE2BAEB14F1453C14D1559232AE1 +96E15D890DF7FD348441F5E429A875754C6BF0520A787F8E9D8C5415674783CC +CB52005EDED47B57F795BC92FB0522EAB18D23EE028B8D10ED57828C250EB285BFEC6E4A4BE8DABCE0D57ECAA20D90C3 +8E5A50C7D5C374445E88752301D20F0B3D6E4988B61D90FD63779B0EDEF9C60D +49D6CB276A0E5FF134A38062503F01351F44CD6455708B50B5F07D03FC477C33 +CB45B56613DF208E79E4E10A6510F07DC1AA49210C7B94E8BBAECD2C35EC6ABC99FB10FD7C96DD6BB6A6685E9FAD93FB +0743F3CC51200F763C242F1956B4D775C092ADF1A5C19ACAE96EB60C2990CF214F8FEA8FC6749286F6BDAB67657C479A +E5608B28A058787D64A145F0362DEFD98CAE0B5A0F22C6DA7C6D278C7B5F95E3 +D4C113D43E7FB6D2EFA9E87471AA76A61B26872607B4AF5B87F9D72113835CE6 +2DC502800BFD21B76126390CA64A08C5432A2254E822F214CDE1EA11430084C5 +CA22C73010B0F1CB8009601BE2AF0B3674D83D5880E4A26C2A3FF0EA0A098CEA +E53B2B102FDB000E9BB747F957156976E5A0C0E3898AA844C13AE8A9CEE7013B +95CF1A46FFC252BE92919531C92BF6A3AA1B16C170DF4461EC54BE07A55C2387 +2EC7E24090F6DFFF6F2F2D8874D2F36AA769995F31F29FBE3B0EA6A16C3EE833 +C1145B1D9AC70761EA902B86455C1BE1BB1153552A1F7327411DECABE538827B +18D596CADD2EE544200A58716C7A4690B658E58CC2B97334740F70894A6C90FA +6A2F8859DFF01E13AC6C5300AD4A2218810FC91A6FB64A560E99FE6C99226AD2 +48D2EB5A08E35AF89A3B7A1CFDEE829FC0C2DDD2E965F4E3D043B0B14CB7825E +91039325D53CDD0236D1CD13047973A013C14B45A32DE0784A73BFABCEAFBCD1 +51B4EAC87C4DC49B007F40D38B8166C388A1AF25E8D2FF6598E8EDE8726E6E14AD88443114D2A0F5E7721E304F3870DA +3A179DDF65B9868CD84C7C04931F40D5D204C97B20DCBF1A70C241E59BFD7F14 +AF538FD16104DCAF03F4DDF05026D6741898DFC247E48A8F72E652DDF2DFD289 +E67F16AEC9D84B6C06F77B806CA6FBC7618BFBECD0D7A04EC3AE1D1DD06BEC5B +FA4D9F8920EBF2F4293C6D4E99083AA4A71A9DDFFDB07EEBDC552DACEC4DA24A +5BF23E630AC81E2CD533803E225BCB3C481B8D650A9858CF2B5219BAE1CDA01A +17B57E8C1032481E69247EA9A0C9EA41F6C0EA9B3F11170CA69C0842423F0455 +96EA848B8527A647DC9DACDB16C5D92B0081EB1CD77B99B47F56C2E249190BD3BE4306333F37487133DD3AD8E57F3092 +B0E9411274D799BE5989D52E74E00DE310CCA2BD47D7A8FA554D66BB04CD787A +D0D28476E3D8832975653D93F545C35278EC1F0B7AD70CA2F36EB476CC207937 +933195E37014619F997B73F5CF4C0110865A822CA8CB0ED1D977D49A1B06A37F +E790CAC2A26452BF941A9E1BABF0A85598EA1CC8F8CFED637C9B40D5E027B518 +49C1F179ABA5BD4F2C45257A33701730E9CC4728677EFF07808ABE31D3CE6FD5C805F43EA5ABB7261B220C82F0794092 diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 99b3c5fb3..cfb92fe8b 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -521,6 +521,15 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( return 1; } break; + case KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1: + man = subghz_protocol_keeloq_common_magic_serial_type1_learning( + fix, manufacture_code->key); + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); + if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { + *manufacture_name = string_get_cstr(manufacture_code->name); + return 1; + } + break; case KEELOQ_LEARNING_UNKNOWN: // Simple Learning decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); @@ -528,6 +537,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( *manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + // Check for mirrored man uint64_t man_rev = 0; uint64_t man_rev_byte = 0; @@ -535,11 +545,13 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( man_rev_byte = (uint8_t)(manufacture_code->key >> i); man_rev = man_rev | man_rev_byte << (56 - i); } + decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = string_get_cstr(manufacture_code->name); return 1; } + //########################### // Normal Learning // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37 diff --git a/lib/subghz/protocols/keeloq_common.c b/lib/subghz/protocols/keeloq_common.c index 0f8c763db..4c0c1d4ef 100644 --- a/lib/subghz/protocols/keeloq_common.c +++ b/lib/subghz/protocols/keeloq_common.c @@ -86,3 +86,15 @@ inline uint64_t data &= 0x0FFFFFFF; return (((uint64_t)data << 32) | data) ^ xor; } + +/** Magic_serial_type1 Learning + * @param data - serial number (28bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +inline uint64_t + subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man) { + return man | ((uint64_t)data << 40) | + ((uint64_t)(((data & 0xff) + ((data >> 8) & 0xFF)) & 0xFF) << 32); +} diff --git a/lib/subghz/protocols/keeloq_common.h b/lib/subghz/protocols/keeloq_common.h index aa07a7f58..448388f0a 100644 --- a/lib/subghz/protocols/keeloq_common.h +++ b/lib/subghz/protocols/keeloq_common.h @@ -21,6 +21,7 @@ #define KEELOQ_LEARNING_NORMAL 2u #define KEELOQ_LEARNING_SECURE 3u #define KEELOQ_LEARNING_MAGIC_XOR_TYPE_1 4u +#define KEELOQ_LEARNING_MAGIC_SERIAL_TYPE_1 5u /** * Simple Learning Encrypt @@ -63,3 +64,11 @@ uint64_t * @return manufacture for this serial number (64bit) */ uint64_t subghz_protocol_keeloq_common_magic_xor_type1_learning(uint32_t data, uint64_t xor); + +/** Magic_serial_type1 Learning + * @param data - serial number (28bit) + * @param man - magic man (64bit) + * @return manufacture for this serial number (64bit) + */ + +uint64_t subghz_protocol_keeloq_common_magic_serial_type1_learning(uint32_t data, uint64_t man); diff --git a/lib/subghz/protocols/magellen.c b/lib/subghz/protocols/magellen.c index 52ef5a724..6dcc83e56 100644 --- a/lib/subghz/protocols/magellen.c +++ b/lib/subghz/protocols/magellen.c @@ -381,7 +381,7 @@ static void subghz_protocol_magellen_get_event_serialize(uint8_t event, string_t "%s%s%s%s%s%s%s%s", ((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") : (event & 0x1 ? " Motion" : " Ok")), - ((event >> 1) & 0x1 ? ", Tamper On (Alarm)" : ""), + ((event >> 1) & 0x1 ? ", Tamper On\n(Alarm)" : ""), ((event >> 2) & 0x1 ? ", ?" : ""), ((event >> 3) & 0x1 ? ", Power On" : ""), ((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""), From f86eada292462754001329c8a4158a7b0e785fe6 Mon Sep 17 00:00:00 2001 From: Kowalski Dragon Date: Sun, 25 Sep 2022 16:39:06 +0200 Subject: [PATCH 3/3] Remove unused headers (#1751) --- applications/services/power/power_service/power.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 85d217f29..757d7718a 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -1,10 +1,7 @@ #include "power_i.h" -#include "views/power_off.h" #include #include -#include -#include #define POWER_OFF_TIMEOUT 90