Logo Search packages:      
Sourcecode: xbox-cromwell version File versions  Download package

LoadLinux.c

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
#include "boot.h"
#include "video.h"
#include "memory_layout.h"
#include <shared.h>
#include <filesys.h>
#include "rc4.h"
#include "sha1.h"
#include "BootFATX.h"
#include "xbox.h"
#include "BootFlash.h"
#include "cpu.h"
#include "BootIde.h"
#include "BootParser.h"
#include "config.h"
#include "iso_fs.h"

//Grub bits
unsigned long saved_drive;
grub_error_t errnum;
unsigned long saved_partition;
unsigned long boot_drive;
      
static int nRet;
static u32 dwKernelSize= 0, dwInitrdSize = 0;


void ExittoLinux(CONFIGENTRY *config);
void startLinux(void* initrdStart, unsigned long initrdSize, const char* appendLine);
void setup(void* KernelPos, void* PhysInitrdPos, unsigned long InitrdSize, const char* kernel_cmdline);
void I2CRebootSlow(void);


void BootPrintConfig(CONFIGENTRY *config) {
      int CharsProcessed=0, CharsSinceNewline=0, Length=0;
      char c;
      printk("  Bootconfig : Kernel  %s \n", config->szKernel);
      VIDEO_ATTR=0xffa8a8a8;
      if (strlen(config->szInitrd)!=0) {
            printk("  Bootconfig : Initrd  %s \n", config->szInitrd);
      }
      printk("  Bootconfig : Kernel commandline :\n");
      Length=strlen(config->szAppend);
      while (CharsProcessed<Length) {
            c = config->szAppend[CharsProcessed];
            CharsProcessed++;
            CharsSinceNewline++;
            if ((CharsSinceNewline>50 && c==' ') || CharsSinceNewline>65) {
                  printk("\n");
                  if (CharsSinceNewline>25) printk("%c",c);
                  CharsSinceNewline = 0;
            } 
            else printk("%c",c);
      }
      printk("\n");
      VIDEO_ATTR=0xffa8a8a8;
}


void memPlaceKernel(const u8* kernelOrg, u32 kernelSize)
{
      unsigned int nSizeHeader=((*(kernelOrg + 0x01f1))+1)*512;
      memcpy((u8 *)KERNEL_SETUP, kernelOrg, nSizeHeader);
      memcpy((u8 *)KERNEL_PM_CODE,(kernelOrg+nSizeHeader),kernelSize-nSizeHeader);
}



CONFIGENTRY* LoadConfigNative(int drive, int partition) {
      CONFIGENTRY *config;
      CONFIGENTRY *currentConfigItem;
      unsigned int nLen;
      u32 dwConfigSize=0;
      char *szGrub;
      
      szGrub = (char *) malloc(265+4);
        memset(szGrub,0,256+4);
        
      memset((u8 *)KERNEL_SETUP,0,2048);

      szGrub[0]=0xff;
      szGrub[1]=0xff;
      szGrub[2]=partition;
      szGrub[3]=0x00;

      errnum=0;
      boot_drive=0;
      saved_drive=0;
      saved_partition=0x0001ffff;
      buf_drive=-1;
      current_partition=0x0001ffff;
      current_drive=drive;
      buf_drive=-1;
      fsys_type = NUM_FSYS;
      disk_read_hook=NULL;
      disk_read_func=NULL;

      //Try for /boot/linuxboot.cfg first
      strcpy(&szGrub[4], "/boot/linuxboot.cfg");
      nRet=grub_open(szGrub);

      if(nRet!=1 || errnum) {
            //Not found - try /linuxboot.cfg
            errnum=0;
            strcpy(&szGrub[4], "/linuxboot.cfg");
            nRet=grub_open(szGrub);
      }
      
      dwConfigSize=filemax;
      if (nRet!=1 || errnum) {
            //File not found
            free(szGrub);
            return NULL;
      }
      
      nLen=grub_read((void *)KERNEL_SETUP, filemax);

      if (nLen > MAX_CONFIG_FILESIZE) nLen = MAX_CONFIG_FILESIZE;
      
      config = ParseConfig((char *)KERNEL_SETUP, nLen, NULL);

      for (currentConfigItem = (CONFIGENTRY*) config; currentConfigItem!=NULL ; currentConfigItem = (CONFIGENTRY*)currentConfigItem->nextConfigEntry) {
            //Set the drive ID and partition IDs for the returned config items
            currentConfigItem->bootType=BOOT_NATIVE;
            currentConfigItem->drive=drive;
            currentConfigItem->partition=partition;
      }
      
      grub_close();
      free(szGrub);
      return config;
}

int LoadKernelNative(CONFIGENTRY *config) {
      char *szGrub;
      u8* tempBuf;

      szGrub = (char *) malloc(265+4);
        memset(szGrub,0,256+4);
        
      memset((u8 *)KERNEL_SETUP,0,2048);

      szGrub[0]=0xff;
      szGrub[1]=0xff;
      szGrub[2]=config->partition;
      szGrub[3]=0x00;

      errnum=0;
      boot_drive=0;
      saved_drive=0;
      saved_partition=0x0001ffff;
      buf_drive=-1;
      current_partition=0x0001ffff;
      current_drive=config->drive;
      buf_drive=-1;
      fsys_type = NUM_FSYS;
      disk_read_hook=NULL;
      disk_read_func=NULL;
      
      I2CTransmitWord(0x10, 0x0c01); // Close DVD tray
      
        strncpy(&szGrub[4], config->szKernel,strlen(config->szKernel));

      nRet=grub_open(szGrub);

      if(nRet!=1) {
            printk("Unable to load kernel, Grub error %d\n", errnum);
            while(1) ;
      }
        
      // Use INITRD_START as temporary location for loading the Kernel 
      tempBuf = (u8*)INITRD_START;
      dwKernelSize=grub_read(tempBuf, MAX_KERNEL_SIZE);
      memPlaceKernel(tempBuf, dwKernelSize);
      grub_close();
      printk(" -  %d bytes...\n", dwKernelSize);

      if(strlen(config->szInitrd)!=0) {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  Loading %s ", config->szInitrd);
            VIDEO_ATTR=0xffa8a8a8;
            strncpy(&szGrub[4], config->szInitrd,sizeof(config->szInitrd));
            nRet=grub_open(szGrub);
            if(filemax==0) {
                  printf("Empty file\n"); while(1);
            }
            if( (nRet!=1) || (errnum)) {
                  printk("Unable to load initrd, Grub error %d\n", errnum);
                  while(1) ;
            }
            printk(" - %d bytes\n", filemax);
            dwInitrdSize=grub_read((void*)INITRD_START, MAX_INITRD_SIZE);
            grub_close();
      } else {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  No initrd from config file");
            VIDEO_ATTR=0xffa8a8a8;
            dwInitrdSize=0;
      }
      free(szGrub);
      return true;
}

CONFIGENTRY* LoadConfigFatX(void) {
      FATXPartition *partition = NULL;
      FATXFILEINFO fileinfo;
      CONFIGENTRY *config=NULL, *currentConfigItem=NULL;
      
      partition = OpenFATXPartition(0,SECTOR_STORE,STORE_SIZE);
      
      if(partition != NULL) {

            if(LoadFATXFile(partition,"/linuxboot.cfg",&fileinfo)) {
                  //Root of E has a linuxboot.cfg in
                  config = (CONFIGENTRY*)malloc(sizeof(CONFIGENTRY));   
                  config = ParseConfig(fileinfo.buffer, fileinfo.fileSize, NULL);
                  free(fileinfo.buffer);
            }
            else if(LoadFATXFile(partition,"/debian/linuxboot.cfg",&fileinfo) ) {
                  //Try in /debian on E
                  config = (CONFIGENTRY*)malloc(sizeof(CONFIGENTRY));   
                  config = ParseConfig(fileinfo.buffer, fileinfo.fileSize, "/debian");
                  free(fileinfo.buffer);
                  CloseFATXPartition(partition);
            }
      } 
      if (config == NULL) return NULL;

      for (currentConfigItem = (CONFIGENTRY*) config; currentConfigItem!= NULL ; currentConfigItem = (CONFIGENTRY*)currentConfigItem->nextConfigEntry) {
            currentConfigItem->bootType = BOOT_FATX;
      }
      return config;
}

int LoadKernelFatX(CONFIGENTRY *config) {

      static FATXPartition *partition = NULL;
      static FATXFILEINFO fileinfo;
      static FATXFILEINFO infokernel;
      static FATXFILEINFO infoinitrd;
      u8* tempBuf;

      memset((u8 *)KERNEL_SETUP,0,4096);
      memset(&fileinfo,0x00,sizeof(fileinfo));
      memset(&infokernel,0x00,sizeof(infokernel));
      memset(&infoinitrd,0x00,sizeof(infoinitrd));

      I2CTransmitWord(0x10, 0x0c01); // Close DVD tray
      
      partition = OpenFATXPartition(0,
                  SECTOR_STORE,
                  STORE_SIZE);
      
      if(partition == NULL) return 0;

      // Use INITRD_START as temporary location for loading the Kernel 
      tempBuf = (u8*)INITRD_START;
      if(! LoadFATXFilefixed(partition,config->szKernel,&infokernel,tempBuf)) {
            printk("Error loading kernel %s\n",config->szKernel);
            while(1);
      } else {
            dwKernelSize = infokernel.fileSize;
            // moving the kernel to its final location
            memPlaceKernel(tempBuf, dwKernelSize);
            
            printk(" -  %d bytes...\n", infokernel.fileRead);
      }

      if(strlen(config->szInitrd)!=0) {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  Loading %s from FATX", config->szInitrd);
            wait_ms(50);
            if(! LoadFATXFilefixed(partition,config->szInitrd,&infoinitrd, (void*)INITRD_START)) {
                  printk("Error loading initrd %s\n",config->szInitrd);
                  while(1);
            }
            
            dwInitrdSize = infoinitrd.fileSize;
            printk(" - %d %d bytes\n", dwInitrdSize,infoinitrd.fileRead);
      } else {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  No initrd from config file");
            VIDEO_ATTR=0xffa8a8a8;
            dwInitrdSize=0;
            printk("");
      }
      return true;
}


CONFIGENTRY *LoadConfigCD(int cdromId) {
      long dwConfigSize=0;
      int n;
      int configLoaded=0;
      CONFIGENTRY *config, *currentConfigItem;

      memset((u8 *)KERNEL_SETUP,0,4096);

      printk("\2Please wait\n\n");
      //See if we already have a CDROM in the drive
      //Try for 8 seconds - takes a while to 'spin up'.
      I2CTransmitWord(0x10, 0x0c01); // close DVD tray
      for (n=0;n<32;++n) {
            dwConfigSize = BootIso9660GetFile(cdromId,"/linuxboo.cfg", (u8 *)KERNEL_SETUP, 0x800);
            if (dwConfigSize>0) {
                  configLoaded=1;
                  break;
            }
            wait_ms(250);
      }

      if (!configLoaded) {
            //Needs to be changed for non-xbox drives, which don't have an eject line
            //Need to send ATA eject command.
            I2CTransmitWord(0x10, 0x0c00); // eject DVD tray
            wait_ms(2000); // Wait for DVD to become responsive to inject command
                  
            VIDEO_ATTR=0xffeeeeff;
            printk("\2Please insert CD and press Button A\n\n");

            while(1) {
                  if (risefall_xpad_BUTTON(TRIGGER_XPAD_KEY_A) == 1) {
                        I2CTransmitWord(0x10, 0x0c01); // close DVD tray
                        wait_ms(500);
                        break;
                  }
                  wait_ms(10);
            
                  //Keep trying to read, in case somebody puts the tray in manually, without pressing A
                  dwConfigSize = BootIso9660GetFile(cdromId,"/linuxboo.cfg", (u8 *)KERNEL_SETUP, 0x800);
                  if (dwConfigSize>0) {
                        configLoaded=1;
                        break;
                  }
            }                                   

            VIDEO_ATTR=0xffffffff;

            printk("Loading linuxboot.cfg from CDROM... \n");
            //Try to load linuxboot.cfg - if we can't after a while, give up.
            for (n=0;n<48;++n) {
                  dwConfigSize = BootIso9660GetFile(cdromId,"/linuxboo.cfg", (u8 *)KERNEL_SETUP, 0x800);
                  if (dwConfigSize>0) {
                        configLoaded=1;
                        break;
                  }
                  wait_ms(250);
            }
      }

      //Failed to load the config file
      if (!configLoaded) return NULL;
        
      // LinuxBoot.cfg File Loaded
      config = ParseConfig((char *)KERNEL_SETUP, dwConfigSize, NULL);
      //Populate the configs with the drive ID
      for (currentConfigItem = (CONFIGENTRY*) config; currentConfigItem!=NULL; currentConfigItem = (CONFIGENTRY*)currentConfigItem->nextConfigEntry) {
            //Set the drive ID and partition IDs for the returned config items
            currentConfigItem->drive=cdromId;
            currentConfigItem->bootType=BOOT_CDROM;
      }
      
      return config;
}

int LoadKernelCdrom(CONFIGENTRY *config) {
      u8* tempBuf;
      
      // Use INITRD_START as temporary location for loading the Kernel 
      tempBuf = (u8*)INITRD_START;
      dwKernelSize=BootIso9660GetFile(config->drive,config->szKernel, tempBuf, MAX_KERNEL_SIZE);

      if( dwKernelSize < 0 ) {
            printk("Not Found, error %d\nHalting\n", dwKernelSize); 
            while(1);
      } else {
            memPlaceKernel(tempBuf, dwKernelSize);
            printk(" -  %d bytes...\n", dwKernelSize);
      }

      if(strlen(config->szInitrd)!=0) {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  Loading %s from CDROM", config->szInitrd);
            VIDEO_ATTR=0xffa8a8a8;
            
            dwInitrdSize=BootIso9660GetFile(config->drive, config->szInitrd, (void*)INITRD_START, MAX_INITRD_SIZE);
            if( dwInitrdSize < 0 ) {
                  printk("Not Found, error %d\nHalting\n", dwInitrdSize); 
                  while(1);
            }
            printk(" - %d bytes\n", dwInitrdSize);
      } else {
            VIDEO_ATTR=0xffd8d8d8;
            printk("  No initrd from config file");
            VIDEO_ATTR=0xffa8a8a8;
            dwInitrdSize=0;
            printk("");
      }
      return true;
}


#ifdef FLASH 
int BootLoadFlashCD(int cdromId) {
      
      u32 dwConfigSize=0;
      int n;
      int cdPresent=0;
      struct SHA1Context context;
      unsigned char SHA1_result[20];
      unsigned char checksum[20];
       
      memset((u8 *)KERNEL_SETUP,0,4096);

      //See if we already have a CDROM in the drive
      //Try for 4 seconds.
      I2CTransmitWord(0x10, 0x0c01); // close DVD tray
      for (n=0;n<16;++n) {
            if((BootIso9660GetFile(cdromId,"/image.bin", (u8 *)KERNEL_SETUP, 0x10)) >=0 ) {
                  cdPresent=1;
                  break;
            }
            wait_ms(250);
      }

      if (!cdPresent) {
            //Needs to be changed for non-xbox drives, which don't have an eject line
            //Need to send ATA eject command.
            I2CTransmitWord(0x10, 0x0c00); // eject DVD tray
            wait_ms(2000); // Wait for DVD to become responsive to inject command
                  
            VIDEO_ATTR=0xffeeeeff;
            
            printk("Please insert CD with image.bin file on, and press Button A\n");

            while(1) {
                  if (risefall_xpad_BUTTON(TRIGGER_XPAD_KEY_A) == 1) {
                        I2CTransmitWord(0x10, 0x0c01); // close DVD tray
                        wait_ms(500);
                        break;
                  }
                    USBGetEvents();
                  wait_ms(10);
            }                                   

            VIDEO_ATTR=0xffffffff;

            // wait until the media is readable
            while(1) {
                  if((BootIso9660GetFile(cdromId,"/image.bin", (u8 *)KERNEL_SETUP, 0x10)) >=0 ) {
                        break;
                  }
                  wait_ms(200);
            }
      }
      printk("CDROM: ");
      printk("Loading bios image from CDROM:/image.bin. \n");
      dwConfigSize=BootIso9660GetFile(cdromId, "/image.bin", (u8 *)KERNEL_PM_CODE, 256*1024);
      
      if( dwConfigSize < 0 ) { //It's not there
            printk("image.bin not found on CDROM... Halting\n");
            while(1) ;
      }

      printk("Image size: %i\n", dwConfigSize);
        if (dwConfigSize!=256*1024) {
            printk("Image is not a 256kB image - aborted\n");
            while (1);
      }
      SHA1Reset(&context);
      SHA1Input(&context,(u8 *)KERNEL_PM_CODE,dwConfigSize);
      SHA1Result(&context,SHA1_result);
      memcpy(checksum,SHA1_result,20);
      printk("Result code: %d\n", BootReflashAndReset((u8*) KERNEL_PM_CODE, (u32) 0, (u32) dwConfigSize));
      SHA1Reset(&context);
      SHA1Input(&context,(void *)LPCFlashadress,dwConfigSize);
      SHA1Result(&context,SHA1_result);
      if (memcmp(checksum,SHA1_result,20)==0) {
            printk("Checksum in flash matches - Flash successful.\nRebooting.");
            wait_ms(2000);
            I2CRebootSlow();  
      } else {
            printk("Checksum in Flash not matching - MISTAKE - Reflashing!\n");
            printk("Result code: %d\n", BootReflashAndReset((u8*) KERNEL_PM_CODE, (u32) 0, (u32) dwConfigSize));
      }
      return 0;
}
#endif //Flash


void ExittoLinux(CONFIGENTRY *config) {
      VIDEO_ATTR=0xff8888a8;
      BootPrintConfig(config);
      printk("     Kernel:  %s\n", (char *)(0x00090200+(*((u16 *)0x9020e)) ));
      printk("\n");
      {
            char *sz="\2Starting Linux\2";
            VIDEO_CURSOR_POSX=((vmode.width-BootVideoGetStringTotalWidth(sz))/2)*4;
            VIDEO_CURSOR_POSY=vmode.height-64;

            VIDEO_ATTR=0xff9f9fbf;
            printk(sz);
      }
      I2cSetFrontpanelLed(I2C_LED_RED0 | I2C_LED_RED1 | I2C_LED_RED2 | I2C_LED_RED3 );
      startLinux((void*)INITRD_START, dwInitrdSize, config->szAppend);
}
      

void startLinux(void* initrdStart, unsigned long initrdSize, const char* appendLine)
{
      int nAta=0;
      // turn off USB
      BootStopUSB();
      setup( (void *)KERNEL_SETUP, initrdStart, initrdSize, appendLine);
        
      if(tsaHarddiskInfo[0].m_bCableConductors == 80) {
            if(tsaHarddiskInfo[0].m_wAtaRevisionSupported&2) nAta=1;
            if(tsaHarddiskInfo[0].m_wAtaRevisionSupported&4) nAta=2;
            if(tsaHarddiskInfo[0].m_wAtaRevisionSupported&8) nAta=3;
            if(tsaHarddiskInfo[0].m_wAtaRevisionSupported&16) nAta=4;
            if(tsaHarddiskInfo[0].m_wAtaRevisionSupported&32) nAta=5;
      } else {
            // force the HDD into a good mode 0x40 ==UDMA | 2 == UDMA2
            nAta=2; // best transfer mode without 80-pin cable
      }
      // nAta=1;
      BootIdeSetTransferMode(0, 0x40 | nAta);
      BootIdeSetTransferMode(1, 0x40 | nAta);

      // orange, people seem to like that colour
      I2cSetFrontpanelLed(
            I2C_LED_GREEN0 | I2C_LED_GREEN1 | I2C_LED_GREEN2 | I2C_LED_GREEN3 |
            I2C_LED_RED0 | I2C_LED_RED1 | I2C_LED_RED2 | I2C_LED_RED3
      );
               
      // Set framebuffer address to final location (for vesafb driver)
      (*(unsigned int*)0xFD600800) = (0xf0000000 | ((xbox_ram*0x100000) - FB_SIZE));
      
      // disable interrupts
      asm volatile ("cli\n");
      
      // clear idt area
      memset((void*)IDT_LOC,0x0,1024*8);
      
      __asm __volatile__ (
      "wbinvd\n"
      
      // Flush the TLB
      "xor %eax, %eax \n"
      "mov %eax, %cr3 \n"
      
      // Load IDT table (0xB0000 = IDT_LOC)
      "lidt       0xB0000\n"
      
      // DR6/DR7: Clear the debug registers
      "xor %eax, %eax \n"
      "mov %eax, %dr6 \n"
      "mov %eax, %dr7 \n"
      "mov %eax, %dr0 \n"
      "mov %eax, %dr1 \n"
      "mov %eax, %dr2 \n"
      "mov %eax, %dr3 \n"
      
      // Kill the LDT, if any
      "xor  %eax, %eax \n"
      "lldt %ax \n"
        
      // Reload CS as 0010 from the new GDT using a far jump
      ".byte 0xEA       \n"   // jmp far 0010:reload_cs
      ".long reload_cs_exit  \n"
      ".word 0x0010  \n"
      
      ".align 16  \n"
      "reload_cs_exit: \n"

      // CS is now a valid entry in the GDT.  Set SS, DS, and ES to valid
      // descriptors, but clear FS and GS as they are not necessary.

      // Set SS, DS, and ES to a data32 segment with maximum limit.
      "movw $0x0018, %ax \n"
      "mov %eax, %ss \n"
      "mov %eax, %ds \n"
      "mov %eax, %es \n"

      // Clear FS and GS
      "xor %eax, %eax \n"
      "mov %eax, %fs \n"
      "mov %eax, %gs \n"

      // Set the stack pointer to give us a valid stack
      "movl $0x03BFFFFC, %esp \n"
      
      "xor  %ebx, %ebx \n"
      "xor  %eax, %eax \n"
      "xor  %ecx, %ecx \n"
      "xor  %edx, %edx \n"
      "xor  %edi, %edi \n"
      "movl       $0x90000, %esi\n"       // kernel setup area
      "ljmp       $0x10, $0x100000\n"     // Jump to Kernel protected mode entry
      );
      
      // We are not longer here, we are already in the Linux loader, we never come back here
      
      // See you again in Linux then      
      while(1);
}


Generated by  Doxygen 1.6.0   Back to index