/* * nLaunch v1.0 * * Copyright (C) 2012-2013 nLaunch team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include // ================================================================================================ // Definitions // ================================================================================================ //! Build options #define DEBUG 2 #define NDLESS 1 //! End of build options #if DEBUG>1 #define S(x) x #else #define S(x) " " #endif #if DEBUG>2 #define EMIT_NOP asm volatile("NOP\n\t") #else #define EMIT_NOP #endif /** * \brief The hex value of a NOP instruction. * \note E1A00000 is usually used for NOP, but we use 00000000 to work around compiler weirdness. */ #define NOP 0x00000000 //! HW_reset from boot2 #define boot2_HW_reset ((void(*)(void))0x11831008) //! load_os from boot2 #define boot2_load_os ((void(*)(uint32_t))0x11802B10) //! rename from boot2 #define boot2_rename ((void(*)(char *, char *))0x11859D08) //! fopen from boot2 #define boot2_fopen ((void *(*)(const char *, const char *))0x11856590) //! fclose from boot2 #define boot2_fclose ((void(*)(void *))0x1185634C) //! unlink from boot2 #define boot2_unlink ((void(*)(const char *))0x1185A238) //! purge_temp_files from boot2 #define boot2_purge_files ((void(*)(const char*))0x1192ACF4) //! display_msg_to_screen from boot2 #define display_msg_to_screen ((void(*)(char *, int, int))0x11801C94) // ================================================================================================ // Variables // ================================================================================================ static uint32_t os_version = 0; static uint8_t do_install_resources = 0; static const char osfilename[] = "/phoenix/install/phoenix.tns"; static const char osupdatefilename[] = "/documents/nlaunch/phoenix.tns"; static const char nlaunchupdatefilename[] = "/documents/nlaunch/nlaunch.tns"; typedef void FILE; // ================================================================================================ // Functions // ================================================================================================ static __attribute__((always_inline)) uint32_t get_word(uint32_t absaddr) { return *((uint32_t *)absaddr); } static __attribute__((always_inline)) void put_word(uint32_t absaddr, uint32_t long_in) { *((uint32_t *)absaddr) = long_in; } //! Write new OS filename to the given address. static __attribute__((noinline)) void write_osfilename(uint32_t address) { unsigned int i; char * src = (char *)osfilename; char * dest = (char *)address; for (i = 0; i < sizeof(osfilename); i++) { *dest++ = *src++; } EMIT_NOP; } //! Make the launcher reboot-proof. static __attribute((always_inline)) void make_reboot_proof(void) { FILE * nlaunchfile; if ((nlaunchfile = boot2_fopen((char *)0x11953920, "r"))) { boot2_fclose(nlaunchfile); if ((nlaunchfile = boot2_fopen((char *)nlaunchupdatefilename, "r"))) { boot2_fclose(nlaunchfile); boot2_unlink((char *)0x11953920); boot2_rename((char *)nlaunchupdatefilename, (char *)0x11953920); boot2_HW_reset(); __builtin_unreachable(); } } else { boot2_rename((char *)0x11952E6C, (char *)0x11953920); do_install_resources = 1; } EMIT_NOP; } //! Update the OS if needed. static __attribute((always_inline)) void update_OS(void) { FILE * osfile; if ((osfile = boot2_fopen((char *)osupdatefilename, "r"))) { boot2_fclose(osfile); boot2_unlink((char *)osfilename); boot2_rename((char *)osupdatefilename, (char *)osfilename); do_install_resources = 1; } EMIT_NOP; } //! Install the OS's resources. static __attribute__((always_inline)) void install_resources(void) { if (do_install_resources) { FILE * osfile; FILE * nlaunchfile; if ( (osfile = boot2_fopen((char *)osfilename, "r")) && (nlaunchfile = boot2_fopen((char *)0x11953920, "r")) ) { boot2_purge_files("/phoenix"); boot2_purge_files("/ti84"); boot2_fclose(osfile); boot2_fclose(nlaunchfile); } write_osfilename(0x11953920); boot2_rename((char *)0x11953920, (char *)0x11952E6C); put_word(0x1192C220, 0xE1A00009); asm volatile( "LDR R0, =0x11952E6C \n\t" "LDR R1, =0x1192C2C8 \n\t" "LDR R9, =0x11952E6C \n\t" "MOV LR, PC \n\t" "LDR PC, =0x1192C120 \n\t" ); boot2_rename((char *)0x11952E6C, (char *)0x11953920); boot2_HW_reset(); __builtin_unreachable(); } EMIT_NOP; } //! Load the OS. static __attribute__((always_inline)) void load_OS(void) { write_osfilename(0x11953920); put_word(0x11800970, 0xE12FFF1E); put_word(0x11802290, 0xEA00003F); put_word(0x118023E4, NOP); put_word(0x118023F4, NOP); put_word(0x11802404, NOP); put_word(0x11802424, NOP); put_word(0x11802930, NOP); put_word(0x11802970, NOP); put_word(0x11802AC4, NOP); boot2_load_os(1); EMIT_NOP; } //! Detect the OS version. static __attribute__((always_inline)) void detect_OS_version(void) { os_version = get_word(0x10000020); #if DEBUG if ( os_version<0x10000000 || os_version>0x12000000 ) { display_msg_to_screen(S("F"),0,0); } #endif EMIT_NOP; } #include "patch.c" //! Jump to OS, without return. static __attribute__((always_inline, noreturn)) void launch_OS(void) { EMIT_NOP; asm volatile( "LDR PC, =0x10000000 \n\t" ); __builtin_unreachable(); } int main(void) { put_word(0x11801204, NOP); asm volatile( "ADD R1, PC, #0x48 \n\t" "LDR R0, =0x11F10000 \n\t" "LDR R2, =0x1000 \n\t" "MOV LR, PC \n\t" "LDR PC, =0x11856CCC \n\t" "LDR R1, =0xE51FF004 \n\t" "LDR R0, =0x11801244 \n\t" "STR R1, [R0] \n\t" "LDR R1, =0x11F10000 \n\t" "LDR R0, =0x11801248 \n\t" "STR R1, [R0] \n\t" "LDR R1, =0x1ACCE551 \n\t" "LDR R0, =0x90060C00 \n\t" "STR R1, [R0] \n\t" "LDR R0, =0x90060008 \n\t" "MOV R1, #0 \n\t" "STR R1, [R0] \n\t" "LDR R0, =0x90060C00 \n\t" "STR R1, [R0] \n\t" "LDR PC, =0x11800000 \n\t" ); { int dummy; // Invalidate caches asm volatile( "0: mrc p15, 0, r15, c7, c10, 3 @ test and clean DCache \n" " bne 0b \n" " mov %0, #0 \n" " mcr p15, 0, %0, c7, c7, 0 @ invalidate ICache and DCache\n" : "=r" (dummy)); } #if DEBUG display_msg_to_screen(S("1"),0,0); #endif make_reboot_proof(); #if DEBUG display_msg_to_screen(S("2"),0,0); #endif update_OS(); #if DEBUG display_msg_to_screen(S("3"),0,0); #endif install_resources(); #if DEBUG display_msg_to_screen(S("4"),0,0); #endif load_OS(); #if DEBUG display_msg_to_screen(S("5"),0,0); #endif detect_OS_version(); #if DEBUG display_msg_to_screen(S("6"),0,0); #endif patch_OS(); #if DEBUG display_msg_to_screen(S("7"),0,0); #endif launch_OS(); }