View of xos/mm/paging.c


XOS | Parent Directory | View | Download

/* Partition de la memoire physique et pagination */
/* Copyright (C) 2008  Emmanuel Varoquaux
 
   This file is part of XOS.
 
   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 3 of the License, or
   (at your option) any later version.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
#include "kmalloc.h"
#include "lowmem.h"
#include "highmem.h"
 
#include <printk.h>
#include <areas.h>
#include <system.h>
#include <system_data_structs.h>
#include <asm.h>
#include <config.h>
#include <i386.h>
#include <util.h>
 
extern int end;
 
static unsigned short ram_size; /* taille de la RAM en Mo */
static unsigned short low_memory_size; /* taille de la memoire basse en Mo */
 
static void *low_memory_page_tables; /* tables des pages de la memoire basse */
static unsigned short nr_low_memory_page_tables;
 
unsigned long main_page_directory[PAGE_SIZE / 4] __attribute__ ((aligned (PAGE_SIZE))); /* table des pages de premier niveau */
 
static void print_human_readable_size(unsigned long size_m)
{
  if (size_m < 1024)
    printk("%luMB", size_m);
  else if (size_m & 511)
    printk("%lu.%luGB", size_m >> 10, (size_m & 1023) * 100 / 1024);
  else if (size_m & 1023)
    printk("%lu.%luGB", size_m >> 10, (size_m & 1023) * 10 / 1024);
  else
    printk("%luGB", size_m >> 10);
}
 
/* Determine la taille de la RAM. */
/* cf http://www.nondot.org/sabre/os/files/Misc/os-faq/os-faq-memory.html/#determine_memory. */
static void count_memory()
{
  unsigned long flags;
  unsigned long addr;
  register unsigned long *volatile mem;
  unsigned long val;
 
  save_control_flags(flags);
  disable_cache();
  ram_size = 0;
  addr = 0;
  do {
    ram_size++;
    addr += 0x100000; /* 1M */
    mem = (unsigned long *)addr;
    val = *mem;
    *mem = 0x55aa55aa;
    if (*mem != 0x55aa55aa)
      break;
    *mem = 0xaa55aa55;
    if (*mem != 0xaa55aa55)
      break;
    *mem = val;
  }
  while (ram_size < 4096);
  restore_control_flags(flags);
}
 
static void setup_low_memory_page_tables()
{
  unsigned long max_page_frame;
  unsigned long *page_table_entry;
  struct page_table_entry_data_struct pte_dat;
  unsigned long page_frame;
 
  max_page_frame = ((low_memory_size * (0x100000 / PAGE_SIZE)) - 1) * PAGE_SIZE;
  page_table_entry = low_memory_page_tables;
 
  /* la page 0 est inaccessible */
  pte_dat.present = 0;
  set_page_table_entry(page_table_entry++, &pte_dat);
 
  /* adresses jusqu'a (low_memory_size * 1M) */
  pte_dat.present = 1;
  pte_dat.rw = 0;
  pte_dat.us = 0;
  pte_dat.accessed = 0;
  pte_dat.dirty = 0;
  pte_dat.avail = 0;
  page_frame = 0;
  do {
    page_frame += PAGE_SIZE;
    pte_dat.page_frame_addr = page_frame;
    set_page_table_entry(page_table_entry++, &pte_dat);
  }
  while (page_frame < max_page_frame);
 
  /* on complete la table de pages courante */
  pte_dat.present = 0;
  while (PAGE_OFFSET((unsigned long)page_table_entry))
    set_page_table_entry(page_table_entry++, &pte_dat);
 
  nr_low_memory_page_tables = ((void *)page_table_entry - low_memory_page_tables) / PAGE_SIZE;
}
 
void init_page_directory(unsigned long *page_directory)
{
  unsigned long *page_table_entry;
  struct page_table_entry_data_struct pte_dat;
 
  clear_page_table(page_directory);
 
  pte_dat.present = 1;
  pte_dat.rw = 1;
  pte_dat.us = 1;
  pte_dat.accessed = 0;
  pte_dat.dirty = 0;
  pte_dat.avail = 0;
  pte_dat.page_frame_addr = (unsigned long)low_memory_page_tables;
  for (page_table_entry = page_directory; page_table_entry < &page_directory[nr_low_memory_page_tables]; page_table_entry++) {
    set_page_table_entry(page_table_entry, &pte_dat);
    pte_dat.page_frame_addr += PAGE_SIZE;
  }
}
 
void setup_paging()
{
  void *dynamic_start;
  void *ptr;
 
  /* buffer cache */
  buffer_start = (void *)PAGE_ALIGN((unsigned long)&end);
  buffer_end = buffer_start + (2UL << 20); /* 2Mo de buffer cache */
  dynamic_start = buffer_end;
 
  /* organisation de la memoire >= dynamic_start */
  count_memory();
  low_memory_size = min(ram_size, USER_BASE >> 20);
  low_memory_page_tables = dynamic_start;
  setup_low_memory_page_tables();
  highmem_init(low_memory_size, ram_size - low_memory_size, low_memory_page_tables + nr_low_memory_page_tables * PAGE_SIZE, &ptr);
  lowmem_init(low_memory_size, ptr);
  kmalloc_init();
 
  /* activation de la pagination */
  init_page_directory(main_page_directory);
  set_pdbr(main_page_directory);
  set_pg();
}
 
void paging_print_info()
{
  printk("RAM size: ");
  print_human_readable_size(ram_size);
  printk("\n");
  lowmem_print_info();
  highmem_print_info();
}
 
void check_paging_empty()
{
  kmalloc_check_empty();
}