/*
 * context.c
 *
 * Written by Vicente Esteve LLoret <viesllo@inf.upv.es>
 * Copyright (C) Jul, 2003 OCERA Consortium.
 *
 * 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 version 2.
 *
 * context managment.
 *
 */

#include <string.h>
#include <arch/page.h>
#include <arch/mprot.h>
#include <arch/memory.h>
#include <rtl_conf.h>
#include <arch/context.h>

#if CONFIG_CONTEXT_MEMORYPROT

extern char _start_context00,_end_context00;
extern char _start_context01,_end_context01;
extern char _start_context02,_end_context02;
extern char _start_context03,_end_context03;
extern char _start_context04,_end_context04;
extern char _start_context05,_end_context05;
extern char _start_context06,_end_context06;
extern char _start_context07,_end_context07;
extern char _start_context08,_end_context08;
extern char _start_context09,_end_context09;

extern page_entry pde[1024];
extern page_entry pte[1024];

 

static struct context_info context[NUM_CONTEXTS] = {
           { &_start_context00, &_end_context00 , 0},
           { &_start_context01, &_end_context01 , 0},
           { &_start_context02, &_end_context02 , 0},
           { &_start_context03, &_end_context03 , 0},
           { &_start_context04, &_end_context04 , 0},
           { &_start_context05, &_end_context05 , 0},
           { &_start_context06, &_end_context06 , 0},
           { &_start_context07, &_end_context07 , 0},
           { &_start_context08, &_end_context08 , 0},
           { &_start_context09, &_end_context09 , 0}
           };

void display_context(void) {
  int i;
  DebugString("Visualizando Contextos                                     ");
  for (i=0;i<20;i++) {
    DebugString("Contexto                                                 ");
    DebugValue(i);
    DebugString("Base                                                     ");
    DebugValue(context[i].base);
    DebugString("END                                                      ");
    DebugValue(context[i].end);
  };
  
}

int map_context(int num,char *ptr,int size) {
  page_entry *pd = (page_entry) context[num].cr3;
  page_entry *pt = (page_entry) (*pd & 0xFFFFF000);
  void *ptrend = ptr;
  
  if (size & RTL_PAGE_MASK)
     ptrend = (void *) ((((unsigned long) ptrend) + size + RTL_PAGE_SIZE) & RTL_PAGE_MASK);
  else
     ptrend = (void *) (((unsigned long) ptrend) + size);
 
  while (ptr < ptrend) {
     pt[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_RW | PAGE_USER;
     ptr = (void *) (((unsigned long) ptr) + RTL_PAGE_SIZE);
  };
  return 0;
}

int get_contextid(void *address) {
 int i;
 for (i=0;i<NUM_CONTEXTS;i++) {
   if (context[i].base != context[i].end) {
     if (((unsigned long) address >= (unsigned long) context[i].base) && 
	  ((unsigned long) address <= (unsigned long) context[i].end)) {
       DebugString("Get_contexid encontro contexto ->                       ");
       DebugValue(i);
       return i;
     };
   };
 };
 return -1; 
};

int get_idle_contextid() {
 int i;
 for (i=0;i<NUM_CONTEXTS;i++) {
   if (context[i].base!=context[i].end) {
     if (context[i].cr3!=0) {
       return i;
     };
   };
 };
  return -1; 
};
unsigned long micr3;

void display_mipt(int num) {
  page_entry *pd;// = v(page_entry) context[num].cr3;
  page_entry *pt;// = (page_entry) (*pd & 0xFFFFF000);
  int i;
  
  DebugString("Viendo mi PT ......");
//  __asm("movl %cr3,%eax 
//	 movl %eax,(micr3)\n");
  pd=micr3;
  pt= (page_entry) (*pd & 0xFFFFF000);
  for (i=0;i<=20;i++) {
    DebugValue(i);
    DebugValue(pt[i]);
  };
  
};

void display_cr3(int num) {
  DebugString("CR3 es -......");
  DebugValue(context[num].cr3);
};

void context_switch(int num) {
  SET_CR3(context[num].cr3);
};

void DisplayPT(page_entry *pt) {
 int i;
 void *ptr=0xb8000;
 DebugString("DisplayPT IO                                      ");
 for (i=address2pteindex(ptr);i<=(address2pteindex(ptr)+5);i++) {
   DebugValue(i);
   DebugValue(pt[i]);
 };
};
int create_context(int num) {
  page_entry *pd;   
  page_entry *pt;
  void *ptr = (void *) context[num].base;
  void *ptrend = (void *) context[num].end;
  
  if (ptr==ptrend)
     return -1;
  
  pd = kmalloc(RTL_PAGE_SIZE,GFP_KERNEL);
  pt = kmalloc(RTL_PAGE_SIZE,GFP_KERNEL);
  
  context[num].cr3 = pd; 
if (num==6) {
  DebugString("CR3 para 6               ");
  DebugValue(context[num].cr3);
};
  memcpy(pd,pde,RTL_PAGE_SIZE);
  memcpy(pt,pte,RTL_PAGE_SIZE);
  
  pd[0] = ((unsigned long) pt & 0xfffff000) | PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL | PAGE_USER;
  
  pt[address2pteindex(pd)] = ((unsigned long) pd & 0xFFFFF000) | PAGE_PRESENT| PAGE_GLOBAL | PAGE_USER;
  pt[address2pteindex(pt)] = ((unsigned long) pt & 0xFFFFF000) | PAGE_PRESENT| PAGE_GLOBAL | PAGE_USER;

  while (ptr < ptrend) {
     pt[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_RW | PAGE_USER;
     ptr = (void *) (((unsigned long) ptr) + RTL_PAGE_SIZE);
  };
if (num==6) {
//  DisplayPT(pt);
};
  return 0;
}
	
void init_context(void)
{
 int i;
// display_context(); 
 for (i=0;i<NUM_CONTEXTS;i++) {
   create_context(i);
 };
 
}

#endif // CONFIG_KERNEL_MEMORYPROT

