solo_main.c 8.34 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */

/*****************************************************************
 * solo_main.c
 *
 *****************************************************************/

#include <filehdr.h>
#include <aouthdr.h>
#include <elf.h>
#include <setjmp.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdio.h>
#include "eventcallback.h"
#include "annotations.h"
#undef SHARED
#include <sys/mman.h>

#include "mipsy.h"
#include "solo.h"
#include "solo_interface.h"
#include "solo_extras.h"
#include "solo_page.h"
#include "solo_anl.h"

#include <stdlib.h>
#include <filehdr.h>
#include <aouthdr.h>
#include <elf.h>
#include <sys/param.h>		/* For btoc/ctob */
#include <sys/sysmacros.h>	/* For btoc/ctob */

extern int  __elfmap(char *, int, int); /* internal LIBC routines */
extern VA SetupStack(int , char **, int, char **, void *);
extern char **_environ;
extern void HWEventsLateInit(void);
extern void SymLoad(char *, char *);

char *AppBrk;			/* The brk point of the application */
char *progName;
extern int SimErrorKeepLogs;

int    soloActiveProcs = 1;
VA     soloHighStack;          
VA     soloLowStack;
int    soloCPUNum;
int    restoringCpt = 0;

#ifdef T5_MODEL
void *entryPC;
#endif

CommArea *comm;

void
DumpMipsyConfig(void)
{
   CPUPrint("Options from Mipsy build:\n--> ");
   CPUPrint(" SOLO");

#ifdef T5_MODEL
   CPUPrint(" T5_MODEL\n");
#endif
   
   SIM_DEBUG(('o', " ANL_DEBUG DEBUG_SYSCALL"));
   CPUPrint("\nDebug options from Mipsy build:\n--> ");

#ifdef DEBUG_DATA
   CPUPrint(" DEBUG_DATA");
#endif

#ifdef DEBUG_DATA_VERBOSE
   CPUPrint(" DEBUG_DATA_VERBOSE");
#endif

  CPUPrint("\n\n");
}

extern void TCLInit(char *initFile);

/*****************************************************************
 * SoloTCLInit
 *****************************************************************/
void 
SoloTclInit(Tcl_Interp *interp)
{
   Tcl_SetVar(interp, "simosPath", ". /morse/m3/hive/simulation/apps/tcl", 
              TCL_GLOBAL_ONLY);
   SymLoad(progName, "soloApp");
}

static void
Usage(void)
{
   fprintf(stderr, "\nusage: solo [-d <debug flags>] application_and_args\n");
}

char *progName = NULL;

/*****************************************************************
 * Entrance to solo mipsy. This main routine will load the application
 * into memory and start its execution.
 *****************************************************************/
int
main(int argc, char **argv)
{
   int i, fd, length, page;
   char *addr;
   struct filehdr *fhdr;
   Elf32_Ehdr *ehdr;
   Elf32_Phdr *phdr;
   char *phdrbase;
   void *entryPC;
   int  elen;
   VA   stackStart;
   uint curbrk = 0;
   uint textStart;
   bool mprotectFailed = FALSE;
   int c;
   const uint pagesize = getpagesize();

   /* This is a hack to make sure ld keeps syscall.o in the link */
   extern int SoloEmulateSyscall(int cpuNum, int syscallNum);
   void *bar = SoloEmulateSyscall;

   /* This is a hack to make sure ld keeps solo_stubs.o in the link */
   extern void *Simrmt_mmap(void *addr, size_t len, int prot, int flags, 
                  char* pathName, off_t off);
   void *bar2 = Simrmt_mmap;

   if (argc < 2) {
      Usage();
      exit(1);
   }

   SimErrorKeepLogs = 0;
   SimErrorInit("cpu.log");

   /* DebugInit("o"); */

   progName = argv[1];

   /* Read the application into low memory */
   if ((fhdr = (struct filehdr *)__elfmap(progName, 0, 0)) ==
       (struct filehdr *) -1) {
      printf("Mipsy: mapping of %s failed\n", progName);
      return -1;
   }

   /* Obtain the entrypoint to the program */
   ehdr = (Elf32_Ehdr *)fhdr;
   if (!IS_ELF(*ehdr)) {
      printf("Can't handle non-ELF object files\n");
      abort();
   }
   
   entryPC =  (void *) (ehdr->e_entry);
   textStart = ((int)entryPC - ((int)entryPC % pagesize));
   
   phdrbase = (char *) ehdr + (ehdr->e_phoff);
   for (i = 0; i < (int) ehdr->e_phnum; i++) {
      phdr = (Elf32_Phdr *) (phdrbase + (ehdr->e_phentsize*i));
      
      if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W)) {
	 if (phdr->p_vaddr > curbrk )  {
	    curbrk = phdr->p_vaddr + phdr->p_memsz;
	 }
      }
   } 

   /*
    * I want to be able to use the debugger, and it needs permission
    * to write "BREAK" to the text segment. 
    */
   for (page = 0; mprotectFailed == FALSE; page ++) {
      if (mprotect((void *)(textStart + (page * pagesize)), pagesize,
                   PROT_WRITE|PROT_READ|PROT_EXEC)) {
         mprotectFailed = TRUE;
      }
   }
  
   TCLInit("init.solo");

   /*****************************************************************
     DON'T PRINT ANYTHING BEFORE THIS POINT OR SAVEOLDCPULOGS WON'T
     WORK ANYMORE 
     *****************************************************************/ 

   AppBrk = (char *) (((curbrk+pagesize-1) / pagesize) * pagesize);

   /* 
    * Allocate a file to be mapped and used as a shared memory region 
    * for communication between solo mipsy and the application 
    */
   fd = open("/dev/zero", O_RDWR);
   if (fd == -1) {
      CPUError("/dev/zero open (for comm area mapping) failed");
   }
   length = COMM_LENGTH;

   addr = (char *) mmap((void *) COMM_START, length,
                        PROT_READ|PROT_WRITE,
                        MAP_SHARED|MAP_FIXED, fd, 0);
   
   if (addr != (char *) COMM_START) {
      perror("Mapping communication area");
      (void) close(fd);
   }

   CPUPrint("Mipsy: Mapped comm area from %8.8x to %8.8x\n",COMM_START,
            COMM_START+length);

   /*
    * Fill in the communication area.
    */
   comm = (CommArea *) addr;
   comm->SetupCommArea = &SoloSetupCommArea;

   /* 
    * Map a stack in for the application 
    */
   fd = open("/dev/zero", O_RDWR);
   if (fd == -1) {
     printf("/dev/zero open (for stack mapping) failed");
   }
   addr = (char *) mmap((void *) (SOLO_STACK_TOP - SOLO_STACK_SIZE), 
                        SOLO_STACK_SIZE,
                        PROT_READ|PROT_WRITE,
                        MAP_SHARED|MAP_FIXED, fd, 0);
   if (addr != (char *) (SOLO_STACK_TOP - SOLO_STACK_SIZE)) {
      perror("Mapping stack for application");
      (void) close(fd);
      return -1;
   }

#ifdef T5_MODEL
    CPUPrint("*** Installing T5 model entry point in stack at %8.8x: %8.8x\n",
	   SOLO_STACK_TOP - (SOLO_STACK_SIZE/2), entryPC);

    * (unsigned long long *)(SOLO_STACK_TOP - (SOLO_STACK_SIZE/2)) =
	 (unsigned long long) entryPC;
    /* Write the entry vector into the top doubleword of the T5 model stack. */
#endif


   /* 
    * Map an initial heap for the application 
    */

   fd = open("/dev/zero", O_RDWR);
   if (fd == -1) {
     CPUError("brk emulation: /dev/zero open (for heap mmap) failed");
   }
   addr = (char *) mmap((void *) AppBrk, 0x100000,
                        PROT_READ|PROT_WRITE,
                        MAP_SHARED|MAP_FIXED, fd, 0);
   if (addr != (char *) (AppBrk)) {
      perror("Mapping new heap region for application");
      (void) close(fd);
      return -1;
   }
   AppBrk += 0x100000;		/* Indicate the real brk value for me */ 

   /* ---- */

   for (elen = 0; _environ[elen] != 0; elen++) 
      continue;
   
   /* Allow room on the stack for the initial program arguments */
   stackStart = (VA)SOLO_STACK_TOP - 0x1000;
   stackStart = SetupStack(argc-1, argv+1, elen+1, _environ,
			   (void *)stackStart);

   soloHighStack   = stackStart;
   soloLowStack    = stackStart - SOLO_STACK_SIZE;

   /* Print out the invocation line. */
   CPUPrint("Invocation: ");
   for (i=0; i<argc; i++) {
      CPUPrint("%s ", argv[i]);
   }
   CPUPrint("\n");
   CPUPrint("Mipsy: Stack start %#x\n", soloHighStack);

   CPUPrint("Mipsy: Mapped application stack from %#x to %#x\n",
            SOLO_STACK_TOP - SOLO_STACK_SIZE, SOLO_STACK_TOP);

   CPUPrint("COMMSTART= %#x STACK_START= %#x\n", COMM_START, SOLO_STACK_TOP);
   CPUPrint("Mipsy: Mapped comm area from %#x to %#x\n",COMM_START,
            COMM_START+length);
   /* Round to next click (page) */
   CPUPrint("Mipsy: Application heap starts at %#x\n", AppBrk);

   PE = (CPUState *)malloc(TOTAL_CPUS*sizeof(CPUState));
   EventCallbackInit(TOTAL_CPUS);
   
   SoloInitPageTranslation();

   MipsySoloInit();

   DumpMipsyConfig();

   MipsyStartCPU(0, (VA)entryPC, (VA)0, stackStart);
   HWEventsLateInit();

   CPUPrint("Starting Solo Mipsy CPU 1 at PC 0x%x\n", entryPC);
   MipsyRun(0);
   SoloExit();
   return 0;
}