// Requires Ndless 2.0 beta from SVN >= r387. // // This program is a tool for launching (apriori) arbitrary OS from Nspire OS // versions supported by Ndless, without installing them. // I decline any responsibility in users using the program for purposes // potentially unwanted by TI, if such usages are possible. #include #define OS_ZIPFILE_PATH "/documents/ndless/phoenix.raw.zip.tns" //! ZIP local file header format: typedef struct __attribute__((packed)) { uint32_t magic; ///< Local file header signature: 'P', 'K', 0x03, 0x04 uint16_t minversion; ///< Minimum version needed to extract uint16_t flags; ///< General purpose bit flag uint16_t method; ///< Compression method uint16_t mtime; ///< File last modification time uint16_t mdate; ///< File last modification date uint32_t crc32; ///< CRC-32 uint32_t csize; ///< Compressed size uint32_t usize; ///< Uncompressed size uint16_t namelen; ///< File name length (n) uint16_t extralen; ///< Extra field length (m) } zip_header; //! ZIP magic in little-endian form. #define ZIP_MAGIC (0x04034B50) void errormsg(const char *message) { char title[20]; char msg[150]; ascii2utf16(title, "OSLauncher", sizeof(title)); ascii2utf16(msg, message, sizeof(msg)); show_dialog_box2(0, title, msg); } /** \brief Decompress from file source to file dest until stream ends or EOF. * inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be * allocated for processing, Z_DATA_ERROR if the deflate data is * invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and * the version of the library linked do not match, or Z_ERRNO if there * is an error reading or writing the files. * * Taken from the zpipe.c zlib example. * Modified to write to memory instead of writing to a file. */ #define CHUNK 16384 uint8_t * in; uint8_t * out; uint32_t inf(FILE *source, uint8_t *dest, uint32_t * crc32_val) { int ret; unsigned have; z_stream strm; /* allocate inflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = 0; strm.next_in = Z_NULL; ret = inflateInit2_(&strm, 0xFFFFFFF1, zlibVersion(), sizeof(z_stream)); if (ret != Z_OK) return ret; *crc32_val = crc32(0, Z_NULL, 0); /* decompress until deflate stream ends or end of file */ do { strm.avail_in = fread(in, 1, CHUNK, source); if (ferror(source)) { (void)inflateEnd(&strm); return Z_ERRNO; } if (strm.avail_in == 0) break; strm.next_in = in; /* run inflate() on input until output buffer not full */ do { printf("."); strm.avail_out = CHUNK; strm.next_out = out; ret = inflate(&strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR) { /* state clobbered */ return ret; } switch (ret) { case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd(&strm); return ret; } have = CHUNK - strm.avail_out; memcpy(dest, out, have); dest += have; *crc32_val = crc32(*crc32_val, out, have); } while (strm.avail_out == 0); /* done when inflate() says it's done */ } while (ret != Z_STREAM_END); /* clean up and return */ (void)inflateEnd(&strm); return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; } int main(void) { FILE * ifile; uint8_t * dest = NULL; size_t read_count; uint32_t val; zip_header ziphdr; ifile = fopen(OS_ZIPFILE_PATH, "rb"); if (!ifile) { errormsg("Can't open OS"); return 1; } read_count = fread((void *)&ziphdr, 1, sizeof(ziphdr), ifile); if (read_count < sizeof(ziphdr)) { errormsg("Error reading OS"); goto end; } if (ziphdr.magic != ZIP_MAGIC || ziphdr.method != 0x08 /* DEFLATE */) { errormsg("OS must be a ZIP DEFLATE file"); goto end; } dest = malloc(ziphdr.usize + 2 * CHUNK); if (!dest) { errormsg("Can't allocate memory"); goto end; } in = dest + ziphdr.usize; out = dest + ziphdr.usize + CHUNK; //printf("%lX\n%lu\n%lu\n%lu\n%lu\n", ziphdr.crc32, ziphdr.csize, ziphdr.usize, (uint32_t)ziphdr.namelen, (uint32_t)ziphdr.extralen); if (fseek(ifile, sizeof(zip_header) + ziphdr.namelen + ziphdr.extralen, SEEK_SET)) { errormsg("Error reading OS"); goto end; } if (inf(ifile, dest, &val) != Z_OK) { errormsg("Error decompressing OS"); goto end; } if (val != ziphdr.crc32) { errormsg("OS checksum error"); goto end; } fclose(ifile); // Killing all interrupts is necessary (exercise for the reader: why ?) *((uint32_t *)0xDC00000C) = 0xFFFFFFFF; __builtin_memcpy((void *)0x10000000, dest, ziphdr.usize); // Useful ? __builtin_memcpy((void *)0x00000000, (void *)0x10000000, 0x40); // This is also necessary (exercise for the reader: why ?) *((uint32_t *)0xC000001C) &= ~((1 << 0) | (1 << 11)); // Launch the OS. asm( ".arm \n" "mov lr, pc\n" "ldr pc, =0x10000000\n" ); __builtin_unreachable(); end: free(dest); fclose(ifile); return 1; }