@@ -62,85 +62,151 @@ std::string formatSizeNetwork(u64 size) {
6262 return formatSizeInetrnal (size, 1000.0 );
6363}
6464
65- // Secure Monitor call for IRAM copy (smcAmsIramCopy)
66- static void smcCopyToIram (uintptr_t iram_addr, const void * src_addr, u32 size) {
67- SecmonArgs args = {};
68- args.X [0 ] = 0xF0000201 ; /* smcAmsIramCopy */
69- args.X [1 ] = (u64 )src_addr; /* DRAM address */
70- args.X [2 ] = (u64 )iram_addr; /* IRAM address */
71- args.X [3 ] = size; /* Amount to copy */
72- args.X [4 ] = 1 ; /* 1 = Write */
73- svcCallSecureMonitor (&args);
74- }
65+ // Swap payload.bin with HATS installer and reboot
66+ // This works on both Erista and Mariko since the system loads sd:\payload.bin
67+ bool rebootToPayload (const char * path) {
68+ constexpr const char * PAYLOAD_BIN = " /payload.bin" ;
69+ constexpr const char * PAYLOAD_BAK = " /payload.bak" ;
7570
76- // Set reboot to payload mode
77- static void smcRebootToIramPayload (void ) {
78- splInitialize ();
79- splSetConfig ((SplConfigItem)65001 , 2 ); // NeedsReboot = 2 (reboot to IRAM payload)
80- splExit ();
81- }
71+ log_write (" rebootToPayload: launching HATS installer from: %s\n " , path);
8272
83- bool rebootToPayload (const char * path) {
84- log_write (" rebootToPayload: attempting to load payload from: %s\n " , path);
73+ // Step 1: Check if payload.bin exists
74+ FILE * f_existing = fopen (PAYLOAD_BIN , " rb" );
75+ if (!f_existing) {
76+ log_write (" rebootToPayload: ERROR - %s not found! This system may not be configured correctly.\n " , PAYLOAD_BIN );
77+ log_write (" rebootToPayload: sd:\\ payload.bin should contain hekate for normal boot.\n " );
78+ return false ;
79+ }
80+ fclose (f_existing);
81+
82+ // Step 2: Backup original payload.bin to payload.bak
83+ log_write (" rebootToPayload: backing up %s to %s\n " , PAYLOAD_BIN , PAYLOAD_BAK );
8584
86- // Open the payload file using stdio (simpler, uses fsdev under the hood )
87- FILE * f = fopen (path , " rb" );
88- if (!f ) {
89- log_write (" rebootToPayload: failed to open file \n " );
85+ // Read payload.bin (original hekate )
86+ FILE * f_src = fopen (PAYLOAD_BIN , " rb" );
87+ if (!f_src ) {
88+ log_write (" rebootToPayload: failed to open %s for reading \n " , PAYLOAD_BIN );
9089 return false ;
9190 }
9291
93- // Get file size
94- fseek (f, 0 , SEEK_END );
95- long size = ftell (f);
96- fseek (f, 0 , SEEK_SET );
92+ fseek (f_src, 0 , SEEK_END );
93+ long original_size = ftell (f_src);
94+ fseek (f_src, 0 , SEEK_SET );
9795
98- log_write (" rebootToPayload: payload file size: %ld bytes (max: %u)\n " , size, IRAM_PAYLOAD_MAX_SIZE );
96+ if (original_size <= 0 ) {
97+ log_write (" rebootToPayload: invalid payload.bin size: %ld\n " , original_size);
98+ fclose (f_src);
99+ return false ;
100+ }
99101
100- // Check payload size
101- if (size <= 0 ) {
102- log_write (" rebootToPayload: invalid payload size (<= 0)\n " );
103- fclose (f);
102+ std::vector<u8 > original_payload (original_size);
103+ size_t bytes_read = fread (original_payload.data (), 1 , original_size, f_src);
104+ fclose (f_src);
105+
106+ if (bytes_read != (size_t )original_size) {
107+ log_write (" rebootToPayload: failed to read %s\n " , PAYLOAD_BIN );
104108 return false ;
105109 }
106- if (size > IRAM_PAYLOAD_MAX_SIZE ) {
107- log_write (" rebootToPayload: payload too large (> %u)\n " , IRAM_PAYLOAD_MAX_SIZE );
108- fclose (f);
110+
111+ // Write backup
112+ FILE * f_bak = fopen (PAYLOAD_BAK , " wb" );
113+ if (!f_bak) {
114+ log_write (" rebootToPayload: failed to create %s\n " , PAYLOAD_BAK );
109115 return false ;
110116 }
111117
112- // Read payload in chunks and copy to IRAM
113- alignas (0x1000 ) u8 page_buf[0x1000 ];
114- bool success = true ;
115- size_t offset = 0 ;
116-
117- while (offset < (size_t )size) {
118- size_t bytes_to_read = sizeof (page_buf);
119- if (offset + bytes_to_read > (size_t )size) {
120- bytes_to_read = (size_t )size - offset;
121- }
122-
123- size_t bytes_read = fread (page_buf, 1 , bytes_to_read, f);
124- if (bytes_read == 0 ) {
125- log_write (" rebootToPayload: failed to read payload at offset %zu\n " , offset);
126- success = false ;
127- break ;
128- }
129-
130- smcCopyToIram (AMS_IWRAM_OFFSET + offset, page_buf, bytes_read);
131- offset += bytes_read;
118+ size_t bytes_written = fwrite (original_payload.data (), 1 , original_size, f_bak);
119+ fclose (f_bak);
120+
121+ if (bytes_written != (size_t )original_size) {
122+ log_write (" rebootToPayload: failed to write backup\n " );
123+ remove (PAYLOAD_BAK );
124+ return false ;
132125 }
133126
134- fclose (f );
127+ log_write ( " rebootToPayload: backup created (%ld bytes) \n " , original_size );
135128
136- if (success) {
137- log_write (" rebootToPayload: payload loaded to IRAM, triggering reboot...\n " );
138- smcRebootToIramPayload ();
139- } else {
140- log_write (" rebootToPayload: failed to load payload to IRAM\n " );
129+ // Step 3: Copy HATS installer to payload.bin
130+ log_write (" rebootToPayload: copying HATS installer to %s\n " , PAYLOAD_BIN );
131+
132+ FILE * f_installer = fopen (path, " rb" );
133+ if (!f_installer) {
134+ log_write (" rebootToPayload: failed to open HATS installer: %s\n " , path);
135+ // Restore backup before returning
136+ FILE * f_restore = fopen (PAYLOAD_BIN , " wb" );
137+ fwrite (original_payload.data (), 1 , original_size, f_restore);
138+ fclose (f_restore);
139+ remove (PAYLOAD_BAK );
140+ return false ;
141141 }
142142
143- return success;
143+ fseek (f_installer, 0 , SEEK_END );
144+ long installer_size = ftell (f_installer);
145+ fseek (f_installer, 0 , SEEK_SET );
146+
147+ if (installer_size <= 0 ) {
148+ log_write (" rebootToPayload: invalid HATS installer size: %ld\n " , installer_size);
149+ fclose (f_installer);
150+ // Restore backup
151+ FILE * f_restore = fopen (PAYLOAD_BIN , " wb" );
152+ fwrite (original_payload.data (), 1 , original_size, f_restore);
153+ fclose (f_restore);
154+ remove (PAYLOAD_BAK );
155+ return false ;
156+ }
157+
158+ std::vector<u8 > installer_data (installer_size);
159+ bytes_read = fread (installer_data.data (), 1 , installer_size, f_installer);
160+ fclose (f_installer);
161+
162+ if (bytes_read != (size_t )installer_size) {
163+ log_write (" rebootToPayload: failed to read HATS installer\n " );
164+ // Restore backup
165+ FILE * f_restore = fopen (PAYLOAD_BIN , " wb" );
166+ fwrite (original_payload.data (), 1 , original_size, f_restore);
167+ fclose (f_restore);
168+ remove (PAYLOAD_BAK );
169+ return false ;
170+ }
171+
172+ // Write HATS installer to payload.bin
173+ FILE * f_dst = fopen (PAYLOAD_BIN , " wb" );
174+ if (!f_dst) {
175+ log_write (" rebootToPayload: failed to open %s for writing\n " , PAYLOAD_BIN );
176+ // Restore backup
177+ FILE * f_restore = fopen (PAYLOAD_BIN , " wb" );
178+ fwrite (original_payload.data (), 1 , original_size, f_restore);
179+ fclose (f_restore);
180+ remove (PAYLOAD_BAK );
181+ return false ;
182+ }
183+
184+ bytes_written = fwrite (installer_data.data (), 1 , installer_size, f_dst);
185+ fclose (f_dst);
186+
187+ if (bytes_written != (size_t )installer_size) {
188+ log_write (" rebootToPayload: failed to write HATS installer\n " );
189+ // Restore backup
190+ FILE * f_restore = fopen (PAYLOAD_BIN , " wb" );
191+ fwrite (original_payload.data (), 1 , original_size, f_restore);
192+ fclose (f_restore);
193+ remove (PAYLOAD_BAK );
194+ return false ;
195+ }
196+
197+ // Step 4: Sync filesystem
198+ fsdevCommitDevice (" sdmc" );
199+
200+ log_write (" rebootToPayload: payload swapped (%ld bytes), rebooting...\n " , installer_size);
201+
202+ // Step 5: Reboot - system will load sd:\payload.bin (which is now HATS installer)
203+ log_write (" rebootToPayload: HATS installer will restore hekate after installation\n " );
204+
205+ spsmInitialize ();
206+ spsmShutdown (true );
207+
208+ // Should not reach here
209+ return false ;
144210}
145211
146212} // namespace sphaira::utils
0 commit comments