// Load an elf file and export a section of it to a new file, without // header, padding or checksum. For exporting the .irom0.text library. // Produces error message on failure (so caller doesn't need to). bool ExportElfSection(char *infile, char *outfile, char *name) { bool ret = false; FILE *fd = 0; MyElf_File *elf = 0; // load elf file elf = LoadElf(infile); if (!elf) { goto end_function; } // open output file fd = fopen(outfile, "wb"); if(!fd) { error("Error: Can't open output file '%s' for writing.\r\n", outfile); goto end_function; } // actually do the export ret = WriteElfSection(elf, fd, name, false, false, false, 0); end_function: // clean up if (fd) fclose(fd); UnloadElf(elf); return ret; }
//=============================================================================== // This loads the program "name" into memory, if it exists. //=============================================================================== long DoExec(char *name, char *environment) { struct FCB *fHandle; long argv, argc; int retval = -ENOEXEC; struct Message *FSMsg = ALLOCMSG; char *kname = AllocKMem((size_t) strlen(name) + 6); // Enough space for "/bin" + name strcpy(kname, "/bin/"); strcat(kname, name); // Open file FSMsg->nextMessage = 0; FSMsg->byte = OPENFILE; FSMsg->quad1 = (long) kname; FSMsg->quad2 = (long) fHandle; SendReceiveMessage(FSPort, FSMsg); fHandle = (struct FCB *) FSMsg->quad1; if ((long) fHandle > 0) { char magic[5]; char executable = 0; (void) SeekFile(FSMsg, fHandle, 10, SEEK_SET); (void) ReadFromFile(fHandle, magic, 4); magic[4] = 0; if (!strcmp(magic, "IJ64")) { (void) SeekFile(FSMsg, fHandle, 0, SEEK_SET); LoadFlat(fHandle); executable = 1; } else { (void) SeekFile(FSMsg, fHandle, 0, SEEK_SET); (void) ReadFromFile(fHandle, magic, 4); if (magic[0] == 0x7F) { (void) SeekFile(FSMsg, fHandle, 0, SEEK_SET); LoadElf(FSMsg, fHandle); executable = 1; } } //Close file and deallocate memory for structures FSMsg->nextMessage = 0; FSMsg->byte = CLOSEFILE; FSMsg->quad1 = (long) fHandle; SendReceiveMessage(FSPort, FSMsg); DeallocMem(kname); DeallocMem(FSMsg); if (executable) { long *l; // Process the arguments for argc and argv // Copy environment string to user data space // It occupies the 81 bytes after the current first free memory currentTask->environment = (void *) currentTask->firstfreemem; memcpy(currentTask->environment, environment, 80); currentTask->firstfreemem += 80; argv = (long) currentTask->environment; argc = ParseEnvironmentString(&argv); argv += 80; // Adjust firstfreemem to point to the first free memory location. currentTask->firstfreemem += argc * sizeof(char *); // Build the first MemStruct struct. Is all this necessary? User tasks don't use the kernel memory allocation, do they? l = (long *) (currentTask->firstfreemem); *l = 0; *(l + 1) = -(long) (((sizeof(struct MemStruct) + currentTask->firstfreemem)) % PageSize); asm("mov %0,%%rdi;" "mov %1,%%rsi": : "r"(argc), "r"(argv):"%rax", "%rdi"); return 0; } else return retval;
// Create the main binary firmware image, from specified elf sections. // Can produce for standard standalone app (separate .irom0.text) // or sdk bootloaded apps (integrated .irom0.text). // Choice of type requires appropriately linked elf file. // Produces error message on failure (so caller doesn't need to). bool CreateBinFile(char *elffile, char *imagefile, int bootver, unsigned char mode, unsigned char clock, unsigned char size, bool iromchksum, char *sections[], int numsec) { bool ret = false; int i, pad, len; unsigned char chksum = CHECKSUM_INIT; unsigned char *data = 0; FILE *outfile = 0; MyElf_File *elf = 0; Image_Header imghead; // load elf file elf = LoadElf(elffile); if (!elf) { goto end_function; } // open output file outfile = fopen(imagefile, "wb"); if(outfile == NULL) { error("Error: Failed to open output file '%s' for writing.\r\n", imagefile); goto end_function; } // set options common to standard and boot v1.2+ headers imghead.byte2 = mode; //imghead.byte3 = (int)((int)size << 4 | clock) && 0xff; imghead.byte3 = ((size << 4) | clock) & 0xff; imghead.entry = elf->header.e_entry; debug("Size = %02x\r\n", size); debug("Byte2 = %02x\r\n", imghead.byte2); debug("Byte3 = %02x\r\n", imghead.byte3); debug("Entry = %08x\r\n", imghead.entry); // boot v1.2+ header if (bootver == 2) { // extra header imghead.magic = BIN_MAGIC_IROM; imghead.count = 4; // probably a version number here, not a count if(fwrite(&imghead, 1, sizeof(imghead), outfile) != sizeof(imghead)) { error("Error: Failed to write header to image file.\r\n"); goto end_function; } if(!WriteElfSection(elf, outfile, ".irom0.text", true, true, IMAGE_PADDING, (iromchksum ? &chksum : 0))) { goto end_function; } } // standard header imghead.magic = BIN_MAGIC_FLASH; imghead.count = numsec; // write header if(fwrite(&imghead, 1, sizeof(imghead), outfile) != sizeof(imghead)) { error("Error: Failed to write header to image file.\r\n"); goto end_function; } // add sections for (i = 0; i < numsec; i++) { if(!WriteElfSection(elf, outfile, sections[i], true, false, SECTION_PADDING, &chksum)) { goto end_function; } } // get image length (plus a byte for the checksum) len = ftell(outfile) + 1; // do we need to pad the image? pad = len % IMAGE_PADDING; if (pad > 0) { pad = IMAGE_PADDING - pad; debug("Padding image with %d byte(s).\r\n", pad); if(fwrite(PADDING, 1, pad, outfile) != pad) { error("Error: Failed to write padding to image file.\r\n"); goto end_function; } } // write checksum if(fwrite(&chksum, 1, 1, outfile) != 1) { error("Error: Failed to write checksum to image file.\r\n"); goto end_function; } // boot v1.1 if(bootver == 1) { // write 'ff' padding up to the position of the library len = 0x10000 - ftell(outfile); debug("Adding boot v1.1 padding, %d bytes of '0xff'.\r\n", len); data = (unsigned char*)malloc(len); memset(data, 0xff, len); if(fwrite(data, 1, len, outfile) != len) { error("Error: Failed to write boot v1.1 spacer.\r\n"); goto end_function; } // write the library if(!WriteElfSection(elf, outfile, ".irom0.text", false, false, 0, 0)) { goto end_function; } } // if we got this far everything worked! ret = true; end_function: // clean up if (outfile) fclose(outfile); if (data) free(data); if (elf) UnloadElf(elf); return ret; }
// Create the main binary firmware image, from specified elf sections. // Can produce for standard standalone app (separate .irom0.text) // or sdk bootloaded apps (integrated .irom0.text). // Choice of type requires appropriately linked elf file. // Produces error message on failure (so caller doesn't need to). bool CreateHeaderFile(char *elffile, char *imagefile, char *sections[], int numsec) { bool ret = false; int i; unsigned int j, len; FILE *outfile = 0; MyElf_File *elf = 0; MyElf_Section *sect; unsigned char *bindata = 0; char name[31]; // load elf file elf = LoadElf(elffile); if (!elf) { goto end_function; } // open output file outfile = fopen(imagefile, "wb"); if(outfile == NULL) { error("Error: Failed to open output file '%s' for writing.\r\n", imagefile); goto end_function; } // add entry point fprintf(outfile, "const uint32 entry_addr = 0x%08x;\r\n", elf->header.e_entry); // add sections for (i = 0; i < numsec; i++) { // get elf section header sect = GetElfSection(elf, sections[i]); if(!sect) { error("Error: Section '%s' not found in elf file.\r\n", sections[i]); goto end_function; } // simple name fix name strncpy(name, sect->name, 31); len = strlen(name); for (j = 0; j < len; j++) { if (name[j] == '.') name[j] = '_'; } // add address, length and start the data block debug("Adding section '%s', addr: 0x%08x, size: %d.\r\n", sections[i], sect->address, sect->size); fprintf(outfile, "\r\nconst uint32 %s_addr = 0x%08x;\r\nconst uint32 %s_len = %d;\r\nconst uint8 %s_data[] = {", name, sect->address, name, sect->size, name); // get elf section binary data bindata = GetElfSectionData(elf, sect); if (!bindata) { goto end_function; } // add the data and finish off the block for (j = 0; j < sect->size; j++) { if (j % 16 == 0) fprintf(outfile, "\r\n 0x%02x,", bindata[j]); else fprintf(outfile, " 0x%02x,", bindata[j]); } fprintf(outfile, "\r\n};\r\n"); free(bindata); bindata = 0; } // if we got this far everything worked! ret = true; end_function: // clean up if (outfile) fclose(outfile); if (elf) UnloadElf(elf); if (bindata) free(bindata); return ret; }
int LoadAndStartApplication(UID pid, void *elf_loc, uint64_t elf_size, const char *argv, uint32_t argc, uint64_t arg_len) { ElfInformation elf_info; ElfLoaderError err = LoadElf(elf_loc, elf_size, ElfLimitations_64Bit | ElfLimitations_LSB, pid, &elf_info); if(err != ElfLoaderError_Success) return -1; //Put argv, argc and elf info into at most 4 pages, take the physical address, unmap the page //Map the page to the same virtual address in the target process as read/write //Pass the pointer as a parameter to the thread uint64_t net_size = argc * sizeof(char*) + arg_len + sizeof(struct ElfSetupParameters); if(net_size % PAGE_SIZE) net_size += (PAGE_SIZE - (net_size % PAGE_SIZE)); uint64_t phys_addr = 0; struct ElfSetupParameters *params = NULL;//MAP if(R0_AllocatePages(net_size / PAGE_SIZE, PhysicalMemoryAllocationFlags_None, &phys_addr) != 0) return -3; //Map the memory into the current process to allow editing if(R0_Map(GetCurrentProcessUID(), phys_addr, (uint64_t*)¶ms, net_size, CachingModeWriteBack, MemoryAllocationType_Application | MemoryAllocationType_Phys, MemoryAllocationFlags_NoExec | MemoryAllocationFlags_Read | MemoryAllocationFlags_Write | MemoryAllocationFlags_User | MemoryAllocationFlags_Present)) return -4; //Map the memory into the target process uint64_t target_virt_addr = 0; if(R0_Map(pid, phys_addr, &target_virt_addr, net_size, CachingModeWriteBack, MemoryAllocationType_MMap, MemoryAllocationFlags_NoExec | MemoryAllocationFlags_Read | MemoryAllocationFlags_Write | MemoryAllocationFlags_User | MemoryAllocationFlags_Present)) return -5; params->ver = 1; params->size = net_size; params->page_size = PAGE_SIZE; params->argc = argc; params->rnd_seed = 0; //Set the seed to 0 for now, secondary loader will set it properly params->elf_entry_point = (uint64_t)elf_info.entry_point; uint8_t **argv_base = (uint8_t**)params->argv; uint8_t *arg_loc = (uint8_t*)argv_base + sizeof(char*) * argc; for(uint32_t i = 0; i < argc; i++) { argv_base[i] = (char*)(target_virt_addr + ((uint64_t)arg_loc - (uint64_t)params)); uint32_t len = strlen(argv) + 1; strcpy(arg_loc, argv); argv += len; arg_loc += len; } R0_Unmap(GetCurrentProcessUID(), (uint64_t)params, net_size); // We're no longer following the SysV Linux ABI, so just map in the data and // pass the virtual address. UID tid = 0; int (*entry_point)(void*) = (int(*)(void*))elf_info.entry_point; if(R0_CreateThread(pid, entry_point, (void*)target_virt_addr, &tid) != 0) return -6; return 0; }