// 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. // Own os.h because zlib functions would be redefined #include "ndless_headers/os.h" #include "zlib/zlib.h" #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) { show_msgbox("OSLauncher", message); } void puts_no_interrupts(const char *str) { // The CX uses another UART, so this code will only work for classic Nspires. It must be commented out on CX. volatile unsigned *line_status_reg = (unsigned*)0x90020014; volatile unsigned *xmit_holding_reg = (unsigned*)0x90020000; while(*str) { while(!(*line_status_reg & 0b100000)); // wait for empty xmit holding reg *xmit_holding_reg = *str++; } } void CHECK_ERR(int err, const char* msg, const char *z_msg) { if (err != Z_OK) { puts_no_interrupts("Error: "); puts_no_interrupts(msg); puts_no_interrupts(z_msg); while(1); } } void test_inflate(compr, comprLen, uncompr, uncomprLen) unsigned char *compr, *uncompr; unsigned comprLen, uncomprLen; { int err; z_stream d_stream; /* decompression stream */ d_stream.zalloc = (alloc_func)0; d_stream.zfree = (free_func)0; d_stream.opaque = (voidpf)0; d_stream.next_in = compr; d_stream.avail_in = 0; d_stream.next_out = uncompr; err = inflateInit2_(&d_stream, 0xFFFFFFF1, zlibVersion(), sizeof(z_stream)); CHECK_ERR(err, "inflateInit", d_stream.msg); puts_no_interrupts("Start decompressing...\n"); while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ err = inflate(&d_stream, Z_NO_FLUSH); if (err == Z_STREAM_END) break; CHECK_ERR(err, "inflate", d_stream.msg); } puts_no_interrupts("Decompressing finished.\n"); // OSLauncher will crash when inflateEnd() is used //err = inflateEnd(&d_stream); //CHECK_ERR(err, "inflateEnd", d_stream.msg); } int main(void) { FILE * ifile; uint8_t * source; uint8_t * dest; size_t read_count; 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; } // Allocate RAM for compressed OS source = malloc(ziphdr.csize); if(!source) { errormsg("Can't allocate memory"); goto end; } if (fseek(ifile, sizeof(zip_header) + ziphdr.namelen + ziphdr.extralen, SEEK_SET)) { errormsg("Error reading OS"); goto end; } // Copy compressed OS into RAM fread(source,1,ziphdr.csize,ifile); fclose(ifile); // Set dest to os base address dest = (void*)0x10000000; //volatile unsigned* lcd_control = IO_LCD_CONTROL; puts_no_interrupts("Killing interrupts.\n"); // Killing all interrupts is necessary (exercise for the reader: why ?) *((uint32_t *)0xDC00000C) = 0xFFFFFFFF; // Unzip OS test_inflate(source, ziphdr.csize, dest, ziphdr.usize); __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(source); fclose(ifile); return 1; }