/* * asmloader.c * * Linux Loader for the Palm OS. * * * Copyright (C) 2004 Vinayak R. Borkar * Author: Vinayak R. Borkar [vinayakb@users.sourceforge.net] * * Original version by Romain Goyet [r.goyet@gmail.com] * * 11-Sep-2005, Alex Osborne [bobofdoom@gmail.com] * Updated to work with multiple handhelds. * * Based on the work of: * Nikolay Petukhov - Palm Tungsten T2 * Vladimir Pouzanov - Palm Tungsten T3 * * 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. */ #include #include //#include #include "garux.h" #include "pxa-regs.h" #define SET_TAG_WORD(off, value) *((unsigned long *)((RAM_BASE_ADDRESS + 0x100)+((off)<<2)))=value #define SET_TAG_WORD_BYTE(off, byte, value) *((char *)((RAM_BASE_ADDRESS + 0x100)+((off)<<2)+(byte)))=value STANDALONE_CODE_RESOURCE_ID (0); void startKernel(); void write_atags(char *cmdline); unsigned long bootLinux(const void *emulStateP, char *userData68KP, Call68KFuncType *call68KFuncP) { unsigned long register i; unsigned long register j; unsigned long register krnlSrc; char *cmdline; cmdline = (char*)(userData68KP); krnlSrc = (unsigned long)userData68KP+256; // Disable FIQ, IRQ asm volatile ("mrs r0, cpsr"); asm volatile ("orr r0, r0, #0xc0"); asm volatile ("msr cpsr, r0"); // Machine-specific initialization #if MACHINE_CPU=='OMAP' // OMAP-based PDA #if MACHINE_NAME=='ptt2' // Palm Tungsten T2 //io ports settings for uart3 *((unsigned long*)0xfffe1044)=0xc9fbffff; *((unsigned long*)0xfffce004)=0x00003a0e; //Reset for disable dma LCD //irq reset *((unsigned long*)0xfffecb00)=0x0; *((unsigned long*)0xfffecb04)=0xffffffff; //dmaGlobal reset *((unsigned short*)0xfffedb00)=0x0; *((unsigned short*)0xfffedc00)=0x8; // Set Page table entries, On palm tt2 page table place in sram. *((unsigned long*)0x20010400)=0x10000c1a; *((unsigned long*)0x20010440)=0x11000c1a; #elif MACHINE_NAME=='pte' // Palm Tungsten E // Set Page table entries for 0x10000000 and 0x11000000 to identity. *((unsigned long *)0x4400)=0x10000c1a; *((unsigned long *)0x4440)=0x11000c1a; #endif #elif MACHINE_CPU=='XSCL' // XScale-based PDA // shut off devices to prevent side-effects of DMA corruption // these will be re-enabled by the kernel drivers. #if MACH_NAME != 'ptc' //With palmtc, shut off LDC crashes garux // This needs to be fixed LCCR0 &= ~LCCR0_ENB; // shut off LCD controller #endif GCR |= ~GCR_ACLINK_OFF; // shut off the AC97 audio controlller // reset IRQs in the hope of fixing the bitops.h crash. // from kernel26/arch/arm/mach-pxa/irq.c /* disable all IRQs */ ICMR = 0; /* all IRQs are IRQ, not FIQ */ ICLR = 0; /* clear all GPIO edge detects */ GFER0 = 0; GFER1 = 0; GFER2 = 0; GRER0 = 0; GRER1 = 0; GRER2 = 0; GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; // this does not seem to be required, but if problems occur // add it in. // Set Page table entries for 0xA0000000 and 0xA1000000 to identity. /* *((unsigned long *)0x6800)=0xA0000c1a; // *((unsigned long *)0x6804)=0xA0100c1a; // *((unsigned long *)0x6802)=0xA0080c1a; *((unsigned long *)0x6820)=0xA0800c1a;*/ // *((unsigned long *)0x6824)=0xA0900c1a; /* *((unsigned long *)0x6804)=0xA0100C1A; *((unsigned long *)0x6808)=0xA0200C1A; *((unsigned long *)0x680C)=0xA0300C1A;*/ /* *((unsigned long *)0x6814)=0xA0500C1A; *((unsigned long *)0x6818)=0xA0600C1A; *((unsigned long *)0x681C)=0xA0700C1A;*/ // *((unsigned long *)0x6820)=0xA0C00C1A; /* *((unsigned long *)0x6824)=0xA0900C1A; *((unsigned long *)0x6828)=0xA0A00C1A; *((unsigned long *)0x682C)=0xA0B00C1A; */ // *((unsigned long *)0x7400)=0xA0E00C1A; /* *((unsigned long *)0x6834)=0xA0D00C1A; *((unsigned long *)0x6838)=0xA0E00C1A; *((unsigned long *)0x683C)=0xA0F00C1A;*/ /* *((unsigned long *)0x6840)=0xA1000C1A; *((unsigned long *)0x6844)=0xA1100C1A; *((unsigned long *)0x6848)=0xA1200C1A; *((unsigned long *)0x684C)=0xA1300C1A; *((unsigned long *)0x6850)=0xA1400C1A; *((unsigned long *)0x6854)=0xA1500C1A; *((unsigned long *)0x6858)=0xA1600C1A; *((unsigned long *)0x685C)=0xA1700C1A; *((unsigned long *)0x6860)=0xA1800C1A; *((unsigned long *)0x6864)=0xA1900C1A; *((unsigned long *)0x6868)=0xA1A00C1A; *((unsigned long *)0x686C)=0xA1B00C1A; *((unsigned long *)0x6870)=0xA1C00C1A; *((unsigned long *)0x6874)=0xA1D00C1A; *((unsigned long *)0x6878)=0xA1E00C1A; *((unsigned long *)0x687C)=0xA1F00C1A;*/ *((unsigned long *)0x6800)=0xa0000c1a; *((unsigned long *)0x6804)=0xa0100c1a; *((unsigned long *)0x6834)=0xa0d00c1a; *((unsigned long *)0x6838)=0xa0e00c1a; *((unsigned long*)(0x92000000)) &= ~LCCR0_ENB; // *((unsigned long *)0x6800)=0xA0000C02; /* *((unsigned long *)0x6800)=0xA0800C1A; *((unsigned long *)0x6800)=0xA0000C1A; */ //*((unsigned long*)(0x92000000)) &= ~LCCR0_ENB; // *((unsigned long *)0x92000000) &= ~LCCR0_ENB; // shut off LCD controller #if MACHINE_NAME=='pld' // Palm LifeDrive /* And similarly for the extra regs on the PXA27x */ ICMR2 = 0; //ICLR2 = 0; //GFER3 = 0; //GRER3 = 0; //GEDR3 = GEDR3; #endif #endif // Let's flush Instruction and Data cache asm volatile ("mov r0, #0"); asm volatile ("mcr p15, 0, r0, c7, c7, 0"); // flush v3/v4 cache asm volatile ("mcr p15, 0, r0, c8, c7, 0"); // flush v4 TLB // Wait a bit. for(i=0 ; i<100000 ; i++); // Copy the kernel to memory starting at MEM_BASE_ADDRESS // In reality we want to copy the image to MEM_BASE_ADDRESS + 0x8000, but // that location holds a second level page table. So if we try to copy directly // to the final destination, the system crashes due to a corrupted second level // page table. So we temporarily copy it way out into MEM_BASE_ADDRESS + 0x1000000 // first. // // Assumption: 0x1000000 is way out and does not trample on either // the code nor kernel data. for(i=0 ; i // and , the offset needs to change. // asm volatile ("add %0, pc, #0x60" : "=r" (j)); for(i=0 ; i<512 ; i++) { *((char *)(RAM_BASE_ADDRESS+0x00001000+i))=*((char *)(i+j)); } asm volatile ("mov lr, %0;" "add pc, lr, #0x00001000;" : : "i"(RAM_BASE_ADDRESS)); // asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); // Let's flush Instruction and Data cache asm volatile ("mov r0, #0"); asm volatile ("mcr p15, 0, r0, c7, c7, 0"); // flush v3/v4 cache asm volatile ("mcr p15, 0, r0, c8, c7, 0"); // flush v4 TLB // Wait a bit. for(i=0 ; i<100000 ; i++); // Let's disable the MMU and disable data cache. asm volatile ("mrc p15, 0, r0, c1, c0, 0"); asm volatile ("bic r0, r0, #0x00002300"); // clear bits 13, 9:8 (--V- --RS) asm volatile ("bic r0, r0, #0x00000087"); // clear bits 7, 2:0 (B--- -CAM) asm volatile ("orr r0, r0, #0x00001000"); // set bit 12 (I) I-Cache asm volatile ("mcr p15, 0, r0, c1, c0, 0"); // invalidate TLB asm volatile ("mov r0, #0"); asm volatile ("mcr p15, 0, r0, c8, c7, 0"); // Wait a bit. for(i=0 ; i<100000 ; i++); // Actually copy the kernel for(i=0 ; i I have moved this into a seperate function so as to keep the number of * local variables in bootLinux to a minimum, meaning the compile can use * registers for all of them. * * It's OK, but thanks to my patch we shall not be relying on GCC using * only registers now. */ void write_atags(char *cmdline) { int i=0; int byte; char c; // ATAG_CORE SET_TAG_WORD(i++,0x00000002); SET_TAG_WORD(i++,0x54410001); // ATAG_MEM SET_TAG_WORD(i++,0x00000004); SET_TAG_WORD(i++,0x54410002); SET_TAG_WORD(i++,PHYSICAL_RAM_SIZE); // size SET_TAG_WORD(i++,RAM_BASE_ADDRESS); // start // ATAG_CMDLINE for (byte=0; cmdline[byte]; byte++); byte = (byte+3) & ~3; SET_TAG_WORD(i++,0x00000002+byte/4); SET_TAG_WORD(i++,0x54410009); byte = 0; do { c = *cmdline++; SET_TAG_WORD_BYTE(i,byte,c); if (++byte==4) { byte=0; i++; } } while (c); while (byte>0) { SET_TAG_WORD_BYTE(i,byte,0); if (++byte==4) { byte=0; i++; } } #if MACHINE_CPU=='OMAP' // ATAG_OMAP SET_TAG_WORD(i++,0x00000005); SET_TAG_WORD(i++,0x414f4d50); SET_TAG_WORD(i++,0x4f030005); SET_TAG_WORD(i++,0x030001c2); SET_TAG_WORD(i++,0x00000000); #endif // ATAG_NONE SET_TAG_WORD(i++,0x00000000); SET_TAG_WORD(i++,0x00000000); }