All pastes #71983 Raw Edit

Something

public text v1 · immutable
#71983 ·published 2006-06-26 12:34 UTC
rendered paste body
/*
 * 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 <PceNativeCall.h>
#include <Standalone.h>
//#include <ByteOrderUtils.h>

#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<NUM_KERNEL_PAGES*PAGE_SIZE ; i+=4) {
    *((unsigned long *)(RAM_BASE_ADDRESS+0x01000000+i))=*((unsigned long *)(krnlSrc+i));
  }
  
  write_atags(cmdline);
  
  // FIXME: We arbitrarily add 0x60 to pc and copy 512 bytes starting
  // from there. So if any code is modified between <CRITICAL>
  // and </CRITICAL>, the offset needs to change.
  // <CRITICAL>
  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));
  // </CRITICAL>

    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<NUM_KERNEL_PAGES*PAGE_SIZE ; i+=4) {
      *((unsigned long *)(RAM_BASE_ADDRESS + 0x0008000+i))=*((unsigned long*)(RAM_BASE_ADDRESS+0x01000000+i));
    }

    // Copy initrd
    for(i=0 ; i<SIZE_INITRD ; i+=4) {
      *((unsigned long *)(RAM_BASE_ADDRESS + 0x0400000+i))=*((unsigned long*)(RAM_BASE_ADDRESS+0x01000000+SIZE_KERNEL+i));
    }

    // Wait a bit.
    for(i=0 ; i<10000000 ; i++);


    // Initializing before boot
    asm volatile ("mov r0,     #0");
    asm volatile ("mov r1,     %0" : : "i"(MACHINE_ID_LINUX & 0xFF));
    asm volatile ("orr r1, r1, %0" : : "i"(MACHINE_ID_LINUX & 0xF00));
    
    // ATAGs location
    asm volatile ("mov r2,     %0" : : "i"(RAM_BASE_ADDRESS));
    asm volatile ("add r2, r2, #0x00000100");

    // Jump to the kernel.
    asm volatile ("mov r3,     #0x00008000");
    asm volatile ("orr r3, r3, %0": : "i"(RAM_BASE_ADDRESS));
    asm volatile ("mov pc, r3");

    // We should never get here... Just to make the compiler happy.
    return 0;
}


/**
 * Set the ATAGs.
 *
 * <Alex> 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.
 *
 * <Romain> 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);
}