/* 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 . */
#include "kmalloc.h"
#include "lowmem.h"
#include "highmem.h"
#include
#include
#include
#include
#include
#include
#include
#include
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();
}