/*
    Copyright 2001 (c) by Claudio Jeker,
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.
 
    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.
 
    For further information, please visit http://www.tik.ee.ethz.ch/~topsy
 
    This software is provided under the terms of the GNU General Public 
    Licence. A full copy of the GNU GPL is provided in the file COPYING 
    found in the development root of Topsy.
*/
/*
	
    File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/VMemory/mips/Attic/vm_bootup_hal.c,v $
    Affiliation:           ETH Zuerich, TIK
    Version:               $Revision: 2922 $
    Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $  by: $Author: baderma $
 
*/
#include "vm.h"
#include "vm_pmap.h"
#include "vm_bootup.h"
#include "MemoryLayout.h"
#include "MMHal.h"
#include "mmHalAsm.h"

#include "cpu.h"
#include "asm.h"

#include "Error.h"
#include "Assert.h"

/* ia32 topsyheader (used in user.bin)*/
#include "headerLayout.h"
typedef struct topsyheader_s
{
  char          name[16];
  uint64        textstart;
  uint64        textsize;
  uint64        datastart;
  uint64        datasize;
  uint64        bssstart;
  uint64        bsssize;
  uint64        optsegment;
  uint64        optsegmentsize;
  uint64        nop1;
  uint64        nop2;
  uint64        tracksize;
} topsyheader_t;

extern void __segmap(void);

/* cr3 flags */
#define CR3_FLAGS_PWT   0x08    /* Page Write-Through */
#define CR3_FLAGS_PCD   0x10    /* Page Cache Disable */

void vm_MMU_or_HELL(struct vm_pmap *vm_pmap)
{
  int flags = 0;

  printf("Setting PDBR to 0x%08x\n", vm_pmap->pdir_base_p);
  __set_PDBR( (int)vm_pmap->pdir_base_p | flags);
 
  printf("Activating MMU...\n");
  __activate_MMU();

  return;
}

int vm_get_physmap(struct vm_physmap **p)
{
  volatile unsigned long lmem  = __maxPhysMem();
  int i = 0;

  *p = (struct vm_physmap*)(address_t)BOOTSTACKBOTTOM;
  (*p)[i].start = PAGENUMBER(PHYSMEM_BASE);   // start of physical memory
  (*p)[i++].end = PAGENUMBER(K2SEG_BASE);     // start of hw-io region

  (*p)[i].start = PAGENUMBER(K2SEG_BASE+K2SEG_SIZE);  // end of hw-io region

#ifdef APIC
  if (PHYSMEM_BASE+lmem > APIC_BASE)
  {
    // APIC inside physical memory region
    (*p)[i++].end = PAGENUMBER(APIC_BASE);     // start of apic region
    (*p)[i].start = PAGENUMBER(APIC_BASE)+1;   // end of apic region

    ASSERT(IOAPIC_BASE > APIC_BASE);

    if (PHYSMEM_BASE+lmem > IOAPIC_BASE)
    {
      // I/O-APIC inside physical memory region
      (*p)[i++].end = PAGENUMBER(IOAPIC_BASE);      // start of I/O-apic region
      (*p)[i].start = PAGENUMBER(IOAPIC_BASE)+1;   // end of apic region
    }
  }
#endif

  (*p)[i++].end = PAGENUMBER(PHYSMEM_BASE + lmem);      // end of physical memory

  // printf("vm_get_physmap(): *p=0x%05x, p.start=0x%05x, p.end=0x%05x (%iMB)\n", *p, (*p)[0].start, (*p)[0].end, (*p)[0].end>>8);

  return i;   // number of entries in the physmap
}

/* Makes a Map of the segments
 */
struct vm_segmap* vm_get_segmap(struct vm_physmap* physmap, int physcnt)
{

  struct vm_segmap* s;
  address_t hint;
  topsyheader_t* topsyheader; /* new Topsyheader, used for user.bin       */ 

  s = (struct vm_segmap*)(physmap + physcnt);
  /* segmap starts right after the physmap */

  s->physmap = physmap;
  s->physcnt = physcnt;

  /* 
   * Extract values from kernel image header */
  topsyheader = (topsyheader_t*)(KERNEL_VMA_BASE + ORG_MARKER);    /* Map Header of file to kernel start */
  if (str_ncmp((char*)TH_NAME,(char*)topsyheader->name,(int)str_len(TH_NAME)))
    PANIC("Wrong MARKER found in kernel image");
  
  // printf("Kernel Header: name=\"%s\" textsize=0x%08x, datasize=0x%08x\n", topsyheader->name, topsyheader->textsize, topsyheader->datasize);

  /* now we need to extract the other values form the kernel image header */
  s->text = (address_t)(unsigned long)topsyheader->textstart;     /* where CoreLoad copies the kernel image to */
  s->textsize = PAGEROUNDUP(topsyheader->textsize);                /* XXX Data Segment is Page aligned */
  hint = s->text + s->textsize;

  s->data = (address_t)(unsigned long)topsyheader->datastart;   /* right after the text */
  s->datasize = PAGEROUNDUP(topsyheader->datasize);

  if ( hint < s->data + s->datasize )
    hint = s->data + s->datasize;

  s->bss = (address_t)(unsigned long)topsyheader->bssstart;
  s->bsssize = topsyheader->bsssize;   /* the bss is in the data segment */

  if ( hint < s->bss + s->bsssize )
    hint = s->bss + s->bsssize;

  s->bootstackbottom = (address_t)BOOTSTACKBOTTOM;
  s->bootstacksize = BOOTSTACKSIZE;

  if ( hint < s->bootstackbottom + s->bootstacksize )
    hint = s->bootstackbottom + s->bootstacksize;

  /* 
   * Extract values from the user image header 
   * user.bin has a topsyheader
   */
  topsyheader = (topsyheader_t*)(unsigned long)(USER_VMA_BASE + ORG_MARKER);    /* Map Header of file to user start */
  if (str_ncmp((char*)TH_NAME,(char*)topsyheader->name,(int)str_len(TH_NAME)))
    PANIC("Wrong MARKER found in user image");

  s->optsegment = (address_t)(unsigned long)USER_VMA_BASE;
  s->optsegmentsize = PAGEROUNDUP(topsyheader->textsize) + 
                      PAGEROUNDUP(topsyheader->datasize) +
                      PAGEROUNDUP(topsyheader->bsssize);

  if (hint < s->optsegment + s->optsegmentsize)
    hint = s->optsegment + s->optsegmentsize;

  s->bootalloccnt = 2;
  s->bootalloc[0].phys = 0x0; /* IDT, GDT... */
  s->bootalloc[0].virt = 0x0;
  s->bootalloc[0].size = KERNEL_VMA_BASE;
  s->bootalloc[0].type = VM_TYPE_VM_STATIC;
  s->bootalloc[1].phys = PAGETOADDR(PAGENUMBER(hint + PAGESIZE));
  s->bootalloc[1].size = 0;

  return s;
}

