/* 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 "tlb.h" #include #include #include #include static int resolve_laddr_alloc(unsigned long laddr, unsigned long **page_table_entry) { struct linear_address_data_struct laddr_dat; unsigned long *page_dir; struct page_table_entry_data_struct pte_dat; unsigned long *page_table; get_linear_address(&laddr, &laddr_dat); /* adresse de la table des pages de premier niveau */ get_pdbr(page_dir); /* adresse de la table des pages de second niveau */ get_page_table_entry(&page_dir[laddr_dat.dir], &pte_dat); if (pte_dat.present) page_table = (unsigned long *)pte_dat.page_frame_addr; else { if (!(page_table = kmalloc(PAGE_SIZE))) return 0; clear_page_table(page_table); 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)page_table; set_page_table_entry(&page_dir[laddr_dat.dir], &pte_dat); } *page_table_entry = &page_table[laddr_dat.page]; return 1; } static int resolve_laddr_noalloc(unsigned long laddr, unsigned long **page_table_entry) { struct linear_address_data_struct laddr_dat; unsigned long *page_dir; struct page_table_entry_data_struct pte_dat; unsigned long *page_table; get_linear_address(&laddr, &laddr_dat); /* adresse de la table des pages de premier niveau */ get_pdbr(page_dir); /* adresse de la table des pages de second niveau */ get_page_table_entry(&page_dir[laddr_dat.dir], &pte_dat); if (!pte_dat.present) return 0; page_table = (unsigned long *)pte_dat.page_frame_addr; *page_table_entry = &page_table[laddr_dat.page]; return 1; } int set_page(unsigned long laddr, unsigned long page_frame, int rw) { unsigned long *page_table_entry; struct page_table_entry_data_struct pte_dat; if (!resolve_laddr_alloc(laddr, &page_table_entry)) return 0; pte_dat.present = 1; pte_dat.rw = rw; pte_dat.us = 1; pte_dat.accessed = 0; pte_dat.dirty = 0; pte_dat.avail = 0; pte_dat.page_frame_addr = page_frame; set_page_table_entry(page_table_entry, &pte_dat); invalidate_entry(laddr); return 1; } int get_page_frame_addr(unsigned long laddr, unsigned long *page_frame) { unsigned long *page_table_entry; struct page_table_entry_data_struct pte_dat; if (!resolve_laddr_noalloc(laddr, &page_table_entry)) return 0; get_page_table_entry(page_table_entry, &pte_dat); if (!pte_dat.present) return 0; *page_frame = pte_dat.page_frame_addr; return 1; } int get_page_rw(unsigned long laddr, int *rw) { unsigned long *page_table_entry; struct page_table_entry_data_struct pte_dat; if (!resolve_laddr_noalloc(laddr, &page_table_entry)) return 0; get_page_table_entry(page_table_entry, &pte_dat); if (!pte_dat.present) return 0; *rw = pte_dat.rw; return 1; } int set_page_rw(unsigned long laddr, int rw) { unsigned long *page_table_entry; struct page_table_entry_data_struct pte_dat; if (!resolve_laddr_noalloc(laddr, &page_table_entry)) return 0; get_page_table_entry(page_table_entry, &pte_dat); if (!pte_dat.present) return 0; pte_dat.rw = rw; set_page_table_entry(page_table_entry, &pte_dat); invalidate_entry(laddr); return 1; } void del_page(unsigned long laddr) { unsigned long *page_table_entry; struct page_table_entry_data_struct pte_dat; if (!resolve_laddr_noalloc(laddr, &page_table_entry)) return; get_page_table_entry(page_table_entry, &pte_dat); pte_dat.present = 0; set_page_table_entry(page_table_entry, &pte_dat); invalidate_entry(laddr); }