| /* |
| * 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 <stdlib.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <inttypes.h> |
| |
| #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; |
| } |
| } |