/*
 * page.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.
 *
 * page managment.
 *
 */


#include <arch/page.h>
#include <arch/mprot.h>
#include <rtl_conf.h>

#if CONFIG_KERNEL_MEMORYPROT

extern char _init_kernel, _end_kernel, _init_tskcontext, _end_tskcontext, _init_allocspace; 

page_entry pde[1024] __attribute__ ((__section__ (".pagetable")));

page_entry pte[1024] __attribute__ ((__section__ (".pagetable")));


void map_pagetable(void) {
  pde[0] = ((unsigned long) pte & 0xfffff000) | PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL | PAGE_USER;
 
  pte[address2pteindex(pde)] = ((unsigned long) pde & 0xFFFFF000) | PAGE_PRESENT| PAGE_GLOBAL | PAGE_USER;
  pte[address2pteindex(pte)] = ((unsigned long) pte & 0xFFFFF000) | PAGE_PRESENT| PAGE_GLOBAL | PAGE_USER;
};

void map_kernelspace(void) {
  void *ptr = (void *) &_init_kernel;
  
  while (ptr < (void *) &_end_kernel) {
    pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_GLOBAL | PAGE_USER;
    ptr = (void *) (((unsigned long) ptr) + RTL_PAGE_SIZE);
  };
};

void map_userspace(void) {
  void *ptr = (void *) &_init_tskcontext;
  while (ptr < (void *) &_end_tskcontext) {
#if CONFIG_CONTEXT_MEMORYPROT
    pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_USER;
#else
    pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL | PAGE_USER;
#endif
    ptr = (void *) (((unsigned long) ptr) + RTL_PAGE_SIZE);
  };
};

void map_allocspace(void) {
  void *ptr = (void *) &_init_allocspace;
  while (ptr < (void *) 0x94000) {
#if CONFIG_CONTEXT_MEMORYPROT
     pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_USER;
#else
     pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_RW | PAGE_GLOBAL | PAGE_USER;
#endif
     
    ptr = (void *) (((unsigned long) ptr) + RTL_PAGE_SIZE);
  };
};

void map_iospace(void) {
  void *ptr = (void *) 0xB8000;
  while (ptr < (void *) 0xC0000) {
    pte[address2pteindex(ptr)] = ((unsigned long) ptr & 0xFFFFF000) | PAGE_PRESENT | PAGE_GLOBAL | PAGE_USER | PAGE_RW;
     ptr = ((unsigned long) ptr) + RTL_PAGE_SIZE;
  };
 
  
};

void enable_pagebit(void) {
  SET_CR4(X86_CR4_PSE | X86_CR4_PGE);
  SET_CR3(pde);
  ENABLE_PAGE();
};

void init_page(void)
{
  map_pagetable();	  
  map_kernelspace();
  map_userspace();
  map_allocspace();
  map_iospace();
  enable_pagebit();
}

#endif // CONFIG_KERNEL_MEMORYPROT

