mmap emulation
[qemu] / exec.c
1 /*
2  *  virtual page mapping
3  * 
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <inttypes.h>
27
28 #include "cpu-i386.h"
29
30 /* XXX: pack the flags in the low bits of the pointer ? */
31 typedef struct PageDesc {
32     struct TranslationBlock *first_tb;
33     unsigned long flags;
34 } PageDesc;
35
36 #define L2_BITS 10
37 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
38
39 #define L1_SIZE (1 << L1_BITS)
40 #define L2_SIZE (1 << L2_BITS)
41
42 unsigned long real_host_page_size;
43 unsigned long host_page_bits;
44 unsigned long host_page_size;
45 unsigned long host_page_mask;
46
47 static PageDesc *l1_map[L1_SIZE];
48
49 void page_init(void)
50 {
51     /* NOTE: we can always suppose that host_page_size >=
52        TARGET_PAGE_SIZE */
53     real_host_page_size = getpagesize();
54     if (host_page_size == 0)
55         host_page_size = real_host_page_size;
56     if (host_page_size < TARGET_PAGE_SIZE)
57         host_page_size = TARGET_PAGE_SIZE;
58     host_page_bits = 0;
59     while ((1 << host_page_bits) < host_page_size)
60         host_page_bits++;
61     host_page_mask = ~(host_page_size - 1);
62 }
63
64 /* dump memory mappings */
65 void page_dump(FILE *f)
66 {
67     unsigned long start, end;
68     int i, j, prot, prot1;
69     PageDesc *p;
70
71     fprintf(f, "%-8s %-8s %-8s %s\n",
72             "start", "end", "size", "prot");
73     start = -1;
74     end = -1;
75     prot = 0;
76     for(i = 0; i <= L1_SIZE; i++) {
77         if (i < L1_SIZE)
78             p = l1_map[i];
79         else
80             p = NULL;
81         for(j = 0;j < L2_SIZE; j++) {
82             if (!p)
83                 prot1 = 0;
84             else
85                 prot1 = p[j].flags;
86             if (prot1 != prot) {
87                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
88                 if (start != -1) {
89                     fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
90                             start, end, end - start, 
91                             prot & PAGE_READ ? 'r' : '-',
92                             prot & PAGE_WRITE ? 'w' : '-',
93                             prot & PAGE_EXEC ? 'x' : '-');
94                 }
95                 if (prot1 != 0)
96                     start = end;
97                 else
98                     start = -1;
99                 prot = prot1;
100             }
101             if (!p)
102                 break;
103         }
104     }
105 }
106
107
108 static inline PageDesc *page_find_alloc(unsigned long address)
109 {
110     unsigned int index;
111     PageDesc **lp, *p;
112
113     index = address >> TARGET_PAGE_BITS;
114     lp = &l1_map[index >> L2_BITS];
115     p = *lp;
116     if (!p) {
117         /* allocate if not found */
118         p = malloc(sizeof(PageDesc) * L2_SIZE);
119         memset(p, 0, sizeof(sizeof(PageDesc) * L2_SIZE));
120         *lp = p;
121     }
122     return p + (index & (L2_SIZE - 1));
123 }
124
125 int page_get_flags(unsigned long address)
126 {
127     unsigned int index;
128     PageDesc *p;
129
130     index = address >> TARGET_PAGE_BITS;
131     p = l1_map[index >> L2_BITS];
132     if (!p)
133         return 0;
134     return p[index & (L2_SIZE - 1)].flags;
135 }
136
137 void page_set_flags(unsigned long start, unsigned long end, int flags)
138 {
139     PageDesc *p;
140     unsigned long addr;
141
142     start = start & TARGET_PAGE_MASK;
143     end = TARGET_PAGE_ALIGN(end);
144     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
145         p = page_find_alloc(addr);
146         p->flags = flags;
147     }
148 }