/* * virtual page mapping * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "cpu-i386.h" /* XXX: pack the flags in the low bits of the pointer ? */ typedef struct PageDesc { struct TranslationBlock *first_tb; unsigned long flags; } PageDesc; #define L2_BITS 10 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) #define L1_SIZE (1 << L1_BITS) #define L2_SIZE (1 << L2_BITS) unsigned long real_host_page_size; unsigned long host_page_bits; unsigned long host_page_size; unsigned long host_page_mask; static PageDesc *l1_map[L1_SIZE]; void page_init(void) { /* NOTE: we can always suppose that host_page_size >= TARGET_PAGE_SIZE */ real_host_page_size = getpagesize(); if (host_page_size == 0) host_page_size = real_host_page_size; if (host_page_size < TARGET_PAGE_SIZE) host_page_size = TARGET_PAGE_SIZE; host_page_bits = 0; while ((1 << host_page_bits) < host_page_size) host_page_bits++; host_page_mask = ~(host_page_size - 1); } /* dump memory mappings */ void page_dump(FILE *f) { unsigned long start, end; int i, j, prot, prot1; PageDesc *p; fprintf(f, "%-8s %-8s %-8s %s\n", "start", "end", "size", "prot"); start = -1; end = -1; prot = 0; for(i = 0; i <= L1_SIZE; i++) { if (i < L1_SIZE) p = l1_map[i]; else p = NULL; for(j = 0;j < L2_SIZE; j++) { if (!p) prot1 = 0; else prot1 = p[j].flags; if (prot1 != prot) { end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); if (start != -1) { fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", start, end, end - start, prot & PAGE_READ ? 'r' : '-', prot & PAGE_WRITE ? 'w' : '-', prot & PAGE_EXEC ? 'x' : '-'); } if (prot1 != 0) start = end; else start = -1; prot = prot1; } if (!p) break; } } } static inline PageDesc *page_find_alloc(unsigned long address) { unsigned int index; PageDesc **lp, *p; index = address >> TARGET_PAGE_BITS; lp = &l1_map[index >> L2_BITS]; p = *lp; if (!p) { /* allocate if not found */ p = malloc(sizeof(PageDesc) * L2_SIZE); memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE)); *lp = p; } return p + (index & (L2_SIZE - 1)); } int page_get_flags(unsigned long address) { unsigned int index; PageDesc *p; index = address >> TARGET_PAGE_BITS; p = l1_map[index >> L2_BITS]; if (!p) return 0; return p[index & (L2_SIZE - 1)].flags; } void page_set_flags(unsigned long start, unsigned long end, int flags) { PageDesc *p; unsigned long addr; start = start & TARGET_PAGE_MASK; end = TARGET_PAGE_ALIGN(end); for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { p = page_find_alloc(addr); p->flags = flags; } }