/* 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(); }