summaryrefslogtreecommitdiff
path: root/bootloader/x1000/boot.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-03-16 15:39:18 +0000
committerAidan MacDonald <amachronic@protonmail.com>2022-03-24 23:40:07 +0000
commit6a6c6083fa69575334282d0c8f5dd688a2282188 (patch)
tree17723690dd5ad1ee55f3a2c1651a138b30fb46a1 /bootloader/x1000/boot.c
parent44fbb1a59363a464d637d93656e9b29858451550 (diff)
downloadrockbox-6a6c6083fa69575334282d0c8f5dd688a2282188.tar.gz
rockbox-6a6c6083fa69575334282d0c8f5dd688a2282188.zip
x1000: bootloader: fix Linux self-extracting kernel boot
Basically, there's longstanding bug in Linux with self-extracting kernels on MIPS which just happened to manifest now on the M3K as a hang on boot. The fix is applied to the M3K and Q1 since they both use this type of kernel image. Change-Id: I17d2bad6eebd677cd6d2e0bf146450c71fcf1229
Diffstat (limited to 'bootloader/x1000/boot.c')
-rw-r--r--bootloader/x1000/boot.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/bootloader/x1000/boot.c b/bootloader/x1000/boot.c
index 153c2277aa..d6dfd4a193 100644
--- a/bootloader/x1000/boot.c
+++ b/bootloader/x1000/boot.c
@@ -148,6 +148,35 @@ void boot_linux(void)
148 * Be careful when modifying this code. 148 * Be careful when modifying this code.
149 */ 149 */
150 150
151#if defined(FIIO_M3K) || defined(SHANLING_Q1)
152uint32_t saved_kernel_entry __attribute__((section(".idata")));
153void kernel_thunk(long, long, long, long) __attribute__((section(".icode")));
154
155void kernel_thunk(long a0, long a1, long a2, long a3)
156{
157 /* cache flush */
158 commit_discard_idcache();
159
160 /* now we can jump to the kernel */
161 typedef void(*entry_fn)(long, long, long, long);
162 entry_fn fn = (entry_fn)saved_kernel_entry;
163 fn(a0, a1, a2, a3);
164 while(1);
165}
166
167static void patch_stub_call(void* patch_addr)
168{
169 uint32_t* code = patch_addr;
170 uint32_t stub_addr = (uint32_t)(void*)kernel_thunk;
171
172 /* generate call to stub */
173 code[0] = 0x3c190000 | (stub_addr >> 16); /* lui t9, stub_hi */
174 code[1] = 0x37390000 | (stub_addr & 0xffff); /* ori t9, t9, stub_lo */
175 code[2] = 0x0320f809; /* jalr t9 */
176 code[3] = 0x00000000; /* nop */
177}
178#endif
179
151static __attribute__((unused)) 180static __attribute__((unused))
152void boot_of_helper(uint32_t addr, uint32_t flash_size, const char* args) 181void boot_of_helper(uint32_t addr, uint32_t flash_size, const char* args)
153{ 182{
@@ -157,6 +186,19 @@ void boot_of_helper(uint32_t addr, uint32_t flash_size, const char* args)
157 if(handle < 0) 186 if(handle < 0)
158 return; 187 return;
159 188
189#if defined(FIIO_M3K) || defined(SHANLING_Q1)
190 /* Fix for targets that use self-extracting kernel images */
191 void* jump_addr = core_get_data(handle);
192 uint32_t entry_addr = mips_linux_stub_get_entry(&jump_addr, img_length);
193 if(entry_addr >= 0xa0000000 || entry_addr < 0x80000000) {
194 splash2(5*HZ, "Kernel patch failed", "Please send bugreport");
195 return;
196 }
197
198 saved_kernel_entry = entry_addr;
199 patch_stub_call(jump_addr);
200#endif
201
160 gui_shutdown(); 202 gui_shutdown();
161 203
162 x1000_dualboot_load_pdma_fw(); 204 x1000_dualboot_load_pdma_fw();