diff packages/hal/arm/arch/current/src/redboot_linux_exec.c @ 212:94b558c9fb67

Merge from eCos master repository on 2002-05-31-00:05:29-BST
author jlarmour
date Fri, 31 May 2002 01:05:53 +0000
parents d2c90368aeef
children ae6f2695b07a
line wrap: on
line diff
--- a/packages/hal/arm/arch/current/src/redboot_linux_exec.c
+++ b/packages/hal/arm/arch/current/src/redboot_linux_exec.c
@@ -91,6 +91,20 @@ RedBoot_cmd("exec",
             do_exec
     );
 
+// CYGARC_HAL_MMU_OFF inserts code to turn off MMU and jump to a physical
+// address. Some ARM implementations may need special handling and define
+// their own version.
+#ifndef CYGARC_HAL_MMU_OFF
+#define CYGARC_HAL_MMU_OFF(__paddr__) \
+  "   mcr p15,0,r0,c7,c10,4\n"        \
+  "   mcr p15,0,r0,c7,c7,0\n"         \
+  "   mrc p15,0,r0,c1,c0,0\n"         \
+  "   bic r0,r0,#0xd\n"               \
+  "   bic r0,r0,#0x1000\n"            \
+  "   mcr p15,0,r0,c1,c0,0\n"         \
+  "   mov pc," #__paddr__ "\n"
+#endif
+
 //
 // Parameter info for Linux kernel
 //   ** C A U T I O N **  This setup must match "asm-arm/setup.h"
@@ -243,9 +257,12 @@ do_exec(int argc, char *argv[])
     struct option_info opts[6];
     char line[8];
     char *cmd_line;
-    struct tag *params = (struct tag *)0x0100;
+    struct tag *params = (struct tag *)CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS;
+    extern char __tramp_start__[], __tramp_end__[];
 
-    entry = (unsigned long)CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS);  // Default Linux execute address
+    // Default physical entry point for Linux is kernel base.
+    entry = (unsigned long)CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS;
+
     base_addr = load_address;
     length = load_address_end - load_address;
     ramdisk_size = 4096*1024;
@@ -339,73 +356,49 @@ do_exec(int argc, char *argv[])
     HAL_ICACHE_INVALIDATE_ALL();
     HAL_DCACHE_INVALIDATE_ALL();
 
-    // Tricky code.  We are currently running with the MMU on and the
-    // memory map convoluted from 1-1.  The trampoline code between
-    // labels 1 and 2 must be copied to RAM and then executed at the
-    // non-mapped address.  Then when the code turns off the MMU, the
-    // control flow is unchanged and control can be passed safely to
-    // the program to be executed.
-    // Note: This only works if phys=virt (or there are appropriate
-    //       double mapping of the memory). This should be rewritten
-    //       so a jump follows immediately after the MMU disable
-    //       operation.
+    // Tricky code. We are currently running with the MMU on and the
+    // memory map possibly convoluted from 1-1.  The trampoline code
+    // between labels __tramp_start__ and __tramp_end__ must be copied
+    // to RAM and then executed at the non-mapped address.
     // 
-    // This magic was created in order to
-    // be able to execute standard Linux kernels with as little
-    // change/perturberance as possible.
-    asm volatile ("\n"                  // Copy code between labels 1-2 to the
-                  " ldr r2,=1f;\n"      // trampoline address...
-                  " ldr r3,=2f;\n"
-                  " mov r5,%0;\n"
-                  "4:\n"
-                  " ldr r1,[r2],#4;\n"
-                  " str r1,[r5],#4;\n"
-                  " cmp r2,r3;\n"
-                  " bne 4b;\n"
-                  " nop;nop;nop;nop;nop;nop;nop;nop;\n"
-                  " mov r5,%1;\n"
-		  " mov r2,%2;\n"
-		  " mov r3,%3;\n"
-                  " mov r7,%4;\n"
-		  " mov r6,%5;\n"
-		  " mov pc,%0;\n"       //... and jump to it.
-                  " \n"
-                  "1:\n"
-                  " mrs r1,cpsr;\n"     // Put processor in IRQ mode
-                  " bic r0,r1,#0x1F;\n"
-                  " orr r0,r0,#0x12;\n"
-                  " msr cpsr,r0;\n"
-                  " msr spsr,r1;\n"
-                  " mov lr,r5;\n"       // Set kernel entry point
-                  " mov sp,r5;\n"       // Give the kernel a stack just below the entry point
-                  " mov r1,#0;\n"       // Turn off MMU and caches
-                  " mcr p15,0,r1,c1,c0;\n"
-                  " nop;nop;nop;\n"
-                  " cmp r2,r6;\n"       // Default kernel load address. Relocate
-                  " beq 10f;\n"         // kernel image there if necessary, and
-		  " cmp r3,#0;\n"       // if size is non-zero
-		  " beq 10f;\n"
-		  "05:\n"
-		  " ldr r4,[r2],#4;\n"
-		  " str r4,[r6],#4;\n"
-		  " sub r3,r3,#4;\n"
-		  " cmp r3,#0;\n"
-		  " bne 05b;\n"
-		  "10:\n"
-                  " mov r0,#0;\n"        // Set board type and start the kernel
-                  " mov r1,r7;\n" 
-                  " movs pc,lr;\n"
-                  "2:\n"
-                  : : 
-                  "r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
-		  "r"(entry),
-                  "r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
-                  "r"(length),
-                  "r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
-                  "r"(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS) : 
-                  "r7","r6","r5","r2","r3","r1");
+    // This magic was created in order to be able to execute standard
+    // Linux kernels with as little change/perturberance as possible.
+
+    // copy the trampline code
+    memcpy((char *)CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS,
+	   __tramp_start__,
+	   __tramp_end__ - __tramp_start__);
+
+    asm volatile (
+        CYGARC_HAL_MMU_OFF(%5)
+        "__tramp_start__:\n"
+        " cmp %1,%4;\n"       // Default kernel load address. Relocate
+        " beq 2f;\n"          // kernel image there if necessary, and
+        " cmp %2,#0;\n"       // if size is non-zero
+        " beq 2f;\n"
+        "1:\n"
+        " ldr r0,[%1],#4;\n"
+        " str r0,[%4],#4;\n"
+        " subs %2,%2,#4;\n"
+        " bne 1b;\n"
+        "2:\n"
+        " mov r0,#0;\n"       // Set board type
+        " mov r1,%3;\n"       // Machine type
+        " mov r2,%6;\n"       // Kernel parameters
+        " mov pc,%0;\n"       // Jump to kernel
+        "__tramp_end__:\n"
+        : : 
+        "r"(entry),
+        "r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
+        "r"(length),
+        "r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
+        "r"(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS),
+        "r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
+        "r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS))
+        : "r0", "r1"
+        );
 }
-
+      
 #endif // HAL_PLATFORM_MACHINE_TYPE - otherwise we do not support this stuff...
 
 // EOF redboot_linux_exec.c