xref: /qemu/system/physmem.c (revision 36bdbe5479cebb5765779a430d14daddddcab871)
154936004Sbellard /*
2fd6ce8f6Sbellard  *  virtual page mapping and translated block handling
354936004Sbellard  *
454936004Sbellard  *  Copyright (c) 2003 Fabrice Bellard
554936004Sbellard  *
654936004Sbellard  * This library is free software; you can redistribute it and/or
754936004Sbellard  * modify it under the terms of the GNU Lesser General Public
854936004Sbellard  * License as published by the Free Software Foundation; either
954936004Sbellard  * version 2 of the License, or (at your option) any later version.
1054936004Sbellard  *
1154936004Sbellard  * This library is distributed in the hope that it will be useful,
1254936004Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1354936004Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1454936004Sbellard  * Lesser General Public License for more details.
1554936004Sbellard  *
1654936004Sbellard  * You should have received a copy of the GNU Lesser General Public
1754936004Sbellard  * License along with this library; if not, write to the Free Software
1854936004Sbellard  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1954936004Sbellard  */
2054936004Sbellard #include <stdlib.h>
2154936004Sbellard #include <stdio.h>
2254936004Sbellard #include <stdarg.h>
2354936004Sbellard #include <string.h>
2454936004Sbellard #include <errno.h>
2554936004Sbellard #include <unistd.h>
2654936004Sbellard #include <inttypes.h>
27fd6ce8f6Sbellard #include <sys/mman.h>
2854936004Sbellard 
29ea041c0eSbellard #include "config.h"
306180a181Sbellard #include "cpu.h"
316180a181Sbellard #include "exec-all.h"
3254936004Sbellard 
33fd6ce8f6Sbellard //#define DEBUG_TB_INVALIDATE
3466e85a21Sbellard //#define DEBUG_FLUSH
35fd6ce8f6Sbellard 
36fd6ce8f6Sbellard /* make various TB consistency checks */
37fd6ce8f6Sbellard //#define DEBUG_TB_CHECK
38fd6ce8f6Sbellard 
39fd6ce8f6Sbellard /* threshold to flush the translated code buffer */
40fd6ce8f6Sbellard #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
41fd6ce8f6Sbellard 
42fd6ce8f6Sbellard #define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
43fd6ce8f6Sbellard 
44fd6ce8f6Sbellard TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
45fd6ce8f6Sbellard TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
46fd6ce8f6Sbellard int nb_tbs;
47eb51d102Sbellard /* any access to the tbs or the page table must use this lock */
48eb51d102Sbellard spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
49fd6ce8f6Sbellard 
50fd6ce8f6Sbellard uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
51fd6ce8f6Sbellard uint8_t *code_gen_ptr;
52fd6ce8f6Sbellard 
5354936004Sbellard /* XXX: pack the flags in the low bits of the pointer ? */
5454936004Sbellard typedef struct PageDesc {
5554936004Sbellard     unsigned long flags;
56fd6ce8f6Sbellard     TranslationBlock *first_tb;
5754936004Sbellard } PageDesc;
5854936004Sbellard 
5954936004Sbellard #define L2_BITS 10
6054936004Sbellard #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
6154936004Sbellard 
6254936004Sbellard #define L1_SIZE (1 << L1_BITS)
6354936004Sbellard #define L2_SIZE (1 << L2_BITS)
6454936004Sbellard 
65fd6ce8f6Sbellard static void tb_invalidate_page(unsigned long address);
6633417e70Sbellard static void io_mem_init(void);
67fd6ce8f6Sbellard 
6854936004Sbellard unsigned long real_host_page_size;
6954936004Sbellard unsigned long host_page_bits;
7054936004Sbellard unsigned long host_page_size;
7154936004Sbellard unsigned long host_page_mask;
7254936004Sbellard 
7354936004Sbellard static PageDesc *l1_map[L1_SIZE];
7454936004Sbellard 
7533417e70Sbellard /* io memory support */
7633417e70Sbellard static unsigned long *l1_physmap[L1_SIZE];
7733417e70Sbellard CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
7833417e70Sbellard CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
7933417e70Sbellard static int io_mem_nb;
8033417e70Sbellard 
8134865134Sbellard /* log support */
8234865134Sbellard char *logfilename = "/tmp/qemu.log";
8334865134Sbellard FILE *logfile;
8434865134Sbellard int loglevel;
8534865134Sbellard 
86b346ff46Sbellard static void page_init(void)
8754936004Sbellard {
8854936004Sbellard     /* NOTE: we can always suppose that host_page_size >=
8954936004Sbellard        TARGET_PAGE_SIZE */
9054936004Sbellard     real_host_page_size = getpagesize();
9154936004Sbellard     if (host_page_size == 0)
9254936004Sbellard         host_page_size = real_host_page_size;
9354936004Sbellard     if (host_page_size < TARGET_PAGE_SIZE)
9454936004Sbellard         host_page_size = TARGET_PAGE_SIZE;
9554936004Sbellard     host_page_bits = 0;
9654936004Sbellard     while ((1 << host_page_bits) < host_page_size)
9754936004Sbellard         host_page_bits++;
9854936004Sbellard     host_page_mask = ~(host_page_size - 1);
9954936004Sbellard }
10054936004Sbellard 
10154936004Sbellard /* dump memory mappings */
10254936004Sbellard void page_dump(FILE *f)
10354936004Sbellard {
10454936004Sbellard     unsigned long start, end;
10554936004Sbellard     int i, j, prot, prot1;
10654936004Sbellard     PageDesc *p;
10754936004Sbellard 
10854936004Sbellard     fprintf(f, "%-8s %-8s %-8s %s\n",
10954936004Sbellard             "start", "end", "size", "prot");
11054936004Sbellard     start = -1;
11154936004Sbellard     end = -1;
11254936004Sbellard     prot = 0;
11354936004Sbellard     for(i = 0; i <= L1_SIZE; i++) {
11454936004Sbellard         if (i < L1_SIZE)
11554936004Sbellard             p = l1_map[i];
11654936004Sbellard         else
11754936004Sbellard             p = NULL;
11854936004Sbellard         for(j = 0;j < L2_SIZE; j++) {
11954936004Sbellard             if (!p)
12054936004Sbellard                 prot1 = 0;
12154936004Sbellard             else
12254936004Sbellard                 prot1 = p[j].flags;
12354936004Sbellard             if (prot1 != prot) {
12454936004Sbellard                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
12554936004Sbellard                 if (start != -1) {
12654936004Sbellard                     fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
12754936004Sbellard                             start, end, end - start,
12854936004Sbellard                             prot & PAGE_READ ? 'r' : '-',
12954936004Sbellard                             prot & PAGE_WRITE ? 'w' : '-',
13054936004Sbellard                             prot & PAGE_EXEC ? 'x' : '-');
13154936004Sbellard                 }
13254936004Sbellard                 if (prot1 != 0)
13354936004Sbellard                     start = end;
13454936004Sbellard                 else
13554936004Sbellard                     start = -1;
13654936004Sbellard                 prot = prot1;
13754936004Sbellard             }
13854936004Sbellard             if (!p)
13954936004Sbellard                 break;
14054936004Sbellard         }
14154936004Sbellard     }
14254936004Sbellard }
14354936004Sbellard 
144fd6ce8f6Sbellard static inline PageDesc *page_find_alloc(unsigned int index)
14554936004Sbellard {
14654936004Sbellard     PageDesc **lp, *p;
14754936004Sbellard 
14854936004Sbellard     lp = &l1_map[index >> L2_BITS];
14954936004Sbellard     p = *lp;
15054936004Sbellard     if (!p) {
15154936004Sbellard         /* allocate if not found */
15254936004Sbellard         p = malloc(sizeof(PageDesc) * L2_SIZE);
153fd6ce8f6Sbellard         memset(p, 0, sizeof(PageDesc) * L2_SIZE);
15454936004Sbellard         *lp = p;
15554936004Sbellard     }
15654936004Sbellard     return p + (index & (L2_SIZE - 1));
15754936004Sbellard }
15854936004Sbellard 
159fd6ce8f6Sbellard static inline PageDesc *page_find(unsigned int index)
16054936004Sbellard {
16154936004Sbellard     PageDesc *p;
16254936004Sbellard 
16354936004Sbellard     p = l1_map[index >> L2_BITS];
16454936004Sbellard     if (!p)
16554936004Sbellard         return 0;
166fd6ce8f6Sbellard     return p + (index & (L2_SIZE - 1));
16754936004Sbellard }
16854936004Sbellard 
169fd6ce8f6Sbellard int page_get_flags(unsigned long address)
170fd6ce8f6Sbellard {
171fd6ce8f6Sbellard     PageDesc *p;
172fd6ce8f6Sbellard 
173fd6ce8f6Sbellard     p = page_find(address >> TARGET_PAGE_BITS);
174fd6ce8f6Sbellard     if (!p)
175fd6ce8f6Sbellard         return 0;
176fd6ce8f6Sbellard     return p->flags;
177fd6ce8f6Sbellard }
178fd6ce8f6Sbellard 
179fd6ce8f6Sbellard /* modify the flags of a page and invalidate the code if
180fd6ce8f6Sbellard    necessary. The flag PAGE_WRITE_ORG is positionned automatically
181fd6ce8f6Sbellard    depending on PAGE_WRITE */
18254936004Sbellard void page_set_flags(unsigned long start, unsigned long end, int flags)
18354936004Sbellard {
18454936004Sbellard     PageDesc *p;
18554936004Sbellard     unsigned long addr;
18654936004Sbellard 
18754936004Sbellard     start = start & TARGET_PAGE_MASK;
18854936004Sbellard     end = TARGET_PAGE_ALIGN(end);
189fd6ce8f6Sbellard     if (flags & PAGE_WRITE)
190fd6ce8f6Sbellard         flags |= PAGE_WRITE_ORG;
191eb51d102Sbellard     spin_lock(&tb_lock);
19254936004Sbellard     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
193fd6ce8f6Sbellard         p = page_find_alloc(addr >> TARGET_PAGE_BITS);
194fd6ce8f6Sbellard         /* if the write protection is set, then we invalidate the code
195fd6ce8f6Sbellard            inside */
196fd6ce8f6Sbellard         if (!(p->flags & PAGE_WRITE) &&
197fd6ce8f6Sbellard             (flags & PAGE_WRITE) &&
198fd6ce8f6Sbellard             p->first_tb) {
199fd6ce8f6Sbellard             tb_invalidate_page(addr);
200fd6ce8f6Sbellard         }
20154936004Sbellard         p->flags = flags;
20254936004Sbellard     }
203eb51d102Sbellard     spin_unlock(&tb_lock);
20454936004Sbellard }
205fd6ce8f6Sbellard 
206b346ff46Sbellard void cpu_exec_init(void)
207fd6ce8f6Sbellard {
208fd6ce8f6Sbellard     if (!code_gen_ptr) {
209fd6ce8f6Sbellard         code_gen_ptr = code_gen_buffer;
210b346ff46Sbellard         page_init();
21133417e70Sbellard         io_mem_init();
212fd6ce8f6Sbellard     }
213fd6ce8f6Sbellard }
214fd6ce8f6Sbellard 
215fd6ce8f6Sbellard /* set to NULL all the 'first_tb' fields in all PageDescs */
216fd6ce8f6Sbellard static void page_flush_tb(void)
217fd6ce8f6Sbellard {
218fd6ce8f6Sbellard     int i, j;
219fd6ce8f6Sbellard     PageDesc *p;
220fd6ce8f6Sbellard 
221fd6ce8f6Sbellard     for(i = 0; i < L1_SIZE; i++) {
222fd6ce8f6Sbellard         p = l1_map[i];
223fd6ce8f6Sbellard         if (p) {
224fd6ce8f6Sbellard             for(j = 0; j < L2_SIZE; j++)
225fd6ce8f6Sbellard                 p[j].first_tb = NULL;
226fd6ce8f6Sbellard         }
227fd6ce8f6Sbellard     }
228fd6ce8f6Sbellard }
229fd6ce8f6Sbellard 
230fd6ce8f6Sbellard /* flush all the translation blocks */
231d4e8164fSbellard /* XXX: tb_flush is currently not thread safe */
232fd6ce8f6Sbellard void tb_flush(void)
233fd6ce8f6Sbellard {
234fd6ce8f6Sbellard     int i;
235fd6ce8f6Sbellard #ifdef DEBUG_FLUSH
236fd6ce8f6Sbellard     printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
237fd6ce8f6Sbellard            code_gen_ptr - code_gen_buffer,
238fd6ce8f6Sbellard            nb_tbs,
239fd6ce8f6Sbellard            (code_gen_ptr - code_gen_buffer) / nb_tbs);
240fd6ce8f6Sbellard #endif
241fd6ce8f6Sbellard     nb_tbs = 0;
242fd6ce8f6Sbellard     for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
243fd6ce8f6Sbellard         tb_hash[i] = NULL;
244fd6ce8f6Sbellard     page_flush_tb();
245fd6ce8f6Sbellard     code_gen_ptr = code_gen_buffer;
246d4e8164fSbellard     /* XXX: flush processor icache at this point if cache flush is
247d4e8164fSbellard        expensive */
248fd6ce8f6Sbellard }
249fd6ce8f6Sbellard 
250fd6ce8f6Sbellard #ifdef DEBUG_TB_CHECK
251fd6ce8f6Sbellard 
252fd6ce8f6Sbellard static void tb_invalidate_check(unsigned long address)
253fd6ce8f6Sbellard {
254fd6ce8f6Sbellard     TranslationBlock *tb;
255fd6ce8f6Sbellard     int i;
256fd6ce8f6Sbellard     address &= TARGET_PAGE_MASK;
257fd6ce8f6Sbellard     for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
258fd6ce8f6Sbellard         for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
259fd6ce8f6Sbellard             if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
260fd6ce8f6Sbellard                   address >= tb->pc + tb->size)) {
261fd6ce8f6Sbellard                 printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
262fd6ce8f6Sbellard                        address, tb->pc, tb->size);
263fd6ce8f6Sbellard             }
264fd6ce8f6Sbellard         }
265fd6ce8f6Sbellard     }
266fd6ce8f6Sbellard }
267fd6ce8f6Sbellard 
268fd6ce8f6Sbellard /* verify that all the pages have correct rights for code */
269fd6ce8f6Sbellard static void tb_page_check(void)
270fd6ce8f6Sbellard {
271fd6ce8f6Sbellard     TranslationBlock *tb;
272fd6ce8f6Sbellard     int i, flags1, flags2;
273fd6ce8f6Sbellard 
274fd6ce8f6Sbellard     for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
275fd6ce8f6Sbellard         for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
276fd6ce8f6Sbellard             flags1 = page_get_flags(tb->pc);
277fd6ce8f6Sbellard             flags2 = page_get_flags(tb->pc + tb->size - 1);
278fd6ce8f6Sbellard             if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
279fd6ce8f6Sbellard                 printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
280fd6ce8f6Sbellard                        tb->pc, tb->size, flags1, flags2);
281fd6ce8f6Sbellard             }
282fd6ce8f6Sbellard         }
283fd6ce8f6Sbellard     }
284fd6ce8f6Sbellard }
285fd6ce8f6Sbellard 
286d4e8164fSbellard void tb_jmp_check(TranslationBlock *tb)
287d4e8164fSbellard {
288d4e8164fSbellard     TranslationBlock *tb1;
289d4e8164fSbellard     unsigned int n1;
290d4e8164fSbellard 
291d4e8164fSbellard     /* suppress any remaining jumps to this TB */
292d4e8164fSbellard     tb1 = tb->jmp_first;
293d4e8164fSbellard     for(;;) {
294d4e8164fSbellard         n1 = (long)tb1 & 3;
295d4e8164fSbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
296d4e8164fSbellard         if (n1 == 2)
297d4e8164fSbellard             break;
298d4e8164fSbellard         tb1 = tb1->jmp_next[n1];
299d4e8164fSbellard     }
300d4e8164fSbellard     /* check end of list */
301d4e8164fSbellard     if (tb1 != tb) {
302d4e8164fSbellard         printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
303d4e8164fSbellard     }
304d4e8164fSbellard }
305d4e8164fSbellard 
306fd6ce8f6Sbellard #endif
307fd6ce8f6Sbellard 
308fd6ce8f6Sbellard /* invalidate one TB */
309fd6ce8f6Sbellard static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
310fd6ce8f6Sbellard                              int next_offset)
311fd6ce8f6Sbellard {
312fd6ce8f6Sbellard     TranslationBlock *tb1;
313fd6ce8f6Sbellard     for(;;) {
314fd6ce8f6Sbellard         tb1 = *ptb;
315fd6ce8f6Sbellard         if (tb1 == tb) {
316fd6ce8f6Sbellard             *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
317fd6ce8f6Sbellard             break;
318fd6ce8f6Sbellard         }
319fd6ce8f6Sbellard         ptb = (TranslationBlock **)((char *)tb1 + next_offset);
320fd6ce8f6Sbellard     }
321fd6ce8f6Sbellard }
322fd6ce8f6Sbellard 
323d4e8164fSbellard static inline void tb_jmp_remove(TranslationBlock *tb, int n)
324d4e8164fSbellard {
325d4e8164fSbellard     TranslationBlock *tb1, **ptb;
326d4e8164fSbellard     unsigned int n1;
327d4e8164fSbellard 
328d4e8164fSbellard     ptb = &tb->jmp_next[n];
329d4e8164fSbellard     tb1 = *ptb;
330d4e8164fSbellard     if (tb1) {
331d4e8164fSbellard         /* find tb(n) in circular list */
332d4e8164fSbellard         for(;;) {
333d4e8164fSbellard             tb1 = *ptb;
334d4e8164fSbellard             n1 = (long)tb1 & 3;
335d4e8164fSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
336d4e8164fSbellard             if (n1 == n && tb1 == tb)
337d4e8164fSbellard                 break;
338d4e8164fSbellard             if (n1 == 2) {
339d4e8164fSbellard                 ptb = &tb1->jmp_first;
340d4e8164fSbellard             } else {
341d4e8164fSbellard                 ptb = &tb1->jmp_next[n1];
342d4e8164fSbellard             }
343d4e8164fSbellard         }
344d4e8164fSbellard         /* now we can suppress tb(n) from the list */
345d4e8164fSbellard         *ptb = tb->jmp_next[n];
346d4e8164fSbellard 
347d4e8164fSbellard         tb->jmp_next[n] = NULL;
348d4e8164fSbellard     }
349d4e8164fSbellard }
350d4e8164fSbellard 
351d4e8164fSbellard /* reset the jump entry 'n' of a TB so that it is not chained to
352d4e8164fSbellard    another TB */
353d4e8164fSbellard static inline void tb_reset_jump(TranslationBlock *tb, int n)
354d4e8164fSbellard {
355d4e8164fSbellard     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
356d4e8164fSbellard }
357d4e8164fSbellard 
358fd6ce8f6Sbellard static inline void tb_invalidate(TranslationBlock *tb, int parity)
359fd6ce8f6Sbellard {
360fd6ce8f6Sbellard     PageDesc *p;
361fd6ce8f6Sbellard     unsigned int page_index1, page_index2;
362d4e8164fSbellard     unsigned int h, n1;
363d4e8164fSbellard     TranslationBlock *tb1, *tb2;
364fd6ce8f6Sbellard 
36536bdbe54Sbellard     tb_invalidated_flag = 1;
36636bdbe54Sbellard 
367fd6ce8f6Sbellard     /* remove the TB from the hash list */
368fd6ce8f6Sbellard     h = tb_hash_func(tb->pc);
369fd6ce8f6Sbellard     tb_remove(&tb_hash[h], tb,
370fd6ce8f6Sbellard               offsetof(TranslationBlock, hash_next));
371fd6ce8f6Sbellard     /* remove the TB from the page list */
372fd6ce8f6Sbellard     page_index1 = tb->pc >> TARGET_PAGE_BITS;
373fd6ce8f6Sbellard     if ((page_index1 & 1) == parity) {
374fd6ce8f6Sbellard         p = page_find(page_index1);
375fd6ce8f6Sbellard         tb_remove(&p->first_tb, tb,
376fd6ce8f6Sbellard                   offsetof(TranslationBlock, page_next[page_index1 & 1]));
377fd6ce8f6Sbellard     }
378fd6ce8f6Sbellard     page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
379fd6ce8f6Sbellard     if ((page_index2 & 1) == parity) {
380fd6ce8f6Sbellard         p = page_find(page_index2);
381fd6ce8f6Sbellard         tb_remove(&p->first_tb, tb,
382fd6ce8f6Sbellard                   offsetof(TranslationBlock, page_next[page_index2 & 1]));
383fd6ce8f6Sbellard     }
384d4e8164fSbellard 
385d4e8164fSbellard     /* suppress this TB from the two jump lists */
386d4e8164fSbellard     tb_jmp_remove(tb, 0);
387d4e8164fSbellard     tb_jmp_remove(tb, 1);
388d4e8164fSbellard 
389d4e8164fSbellard     /* suppress any remaining jumps to this TB */
390d4e8164fSbellard     tb1 = tb->jmp_first;
391d4e8164fSbellard     for(;;) {
392d4e8164fSbellard         n1 = (long)tb1 & 3;
393d4e8164fSbellard         if (n1 == 2)
394d4e8164fSbellard             break;
395d4e8164fSbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
396d4e8164fSbellard         tb2 = tb1->jmp_next[n1];
397d4e8164fSbellard         tb_reset_jump(tb1, n1);
398d4e8164fSbellard         tb1->jmp_next[n1] = NULL;
399d4e8164fSbellard         tb1 = tb2;
400d4e8164fSbellard     }
401d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
402fd6ce8f6Sbellard }
403fd6ce8f6Sbellard 
404fd6ce8f6Sbellard /* invalidate all TBs which intersect with the target page starting at addr */
405fd6ce8f6Sbellard static void tb_invalidate_page(unsigned long address)
406fd6ce8f6Sbellard {
407fd6ce8f6Sbellard     TranslationBlock *tb_next, *tb;
408fd6ce8f6Sbellard     unsigned int page_index;
409fd6ce8f6Sbellard     int parity1, parity2;
410fd6ce8f6Sbellard     PageDesc *p;
411fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE
412fd6ce8f6Sbellard     printf("tb_invalidate_page: %lx\n", address);
413fd6ce8f6Sbellard #endif
414fd6ce8f6Sbellard 
415fd6ce8f6Sbellard     page_index = address >> TARGET_PAGE_BITS;
416fd6ce8f6Sbellard     p = page_find(page_index);
417fd6ce8f6Sbellard     if (!p)
418fd6ce8f6Sbellard         return;
419fd6ce8f6Sbellard     tb = p->first_tb;
420fd6ce8f6Sbellard     parity1 = page_index & 1;
421fd6ce8f6Sbellard     parity2 = parity1 ^ 1;
422fd6ce8f6Sbellard     while (tb != NULL) {
423fd6ce8f6Sbellard         tb_next = tb->page_next[parity1];
424fd6ce8f6Sbellard         tb_invalidate(tb, parity2);
425fd6ce8f6Sbellard         tb = tb_next;
426fd6ce8f6Sbellard     }
427fd6ce8f6Sbellard     p->first_tb = NULL;
428fd6ce8f6Sbellard }
429fd6ce8f6Sbellard 
430fd6ce8f6Sbellard /* add the tb in the target page and protect it if necessary */
431fd6ce8f6Sbellard static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
432fd6ce8f6Sbellard {
433fd6ce8f6Sbellard     PageDesc *p;
434fd6ce8f6Sbellard     unsigned long host_start, host_end, addr, page_addr;
435fd6ce8f6Sbellard     int prot;
436fd6ce8f6Sbellard 
437fd6ce8f6Sbellard     p = page_find_alloc(page_index);
438fd6ce8f6Sbellard     tb->page_next[page_index & 1] = p->first_tb;
439fd6ce8f6Sbellard     p->first_tb = tb;
440fd6ce8f6Sbellard     if (p->flags & PAGE_WRITE) {
441fd6ce8f6Sbellard         /* force the host page as non writable (writes will have a
442fd6ce8f6Sbellard            page fault + mprotect overhead) */
443fd6ce8f6Sbellard         page_addr = (page_index << TARGET_PAGE_BITS);
444fd6ce8f6Sbellard         host_start = page_addr & host_page_mask;
445fd6ce8f6Sbellard         host_end = host_start + host_page_size;
446fd6ce8f6Sbellard         prot = 0;
447fd6ce8f6Sbellard         for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
448fd6ce8f6Sbellard             prot |= page_get_flags(addr);
44961382a50Sbellard #if !defined(CONFIG_SOFTMMU)
450fd6ce8f6Sbellard         mprotect((void *)host_start, host_page_size,
451fd6ce8f6Sbellard                  (prot & PAGE_BITS) & ~PAGE_WRITE);
45261382a50Sbellard #endif
45361382a50Sbellard #if !defined(CONFIG_USER_ONLY)
45461382a50Sbellard         /* suppress soft TLB */
45561382a50Sbellard         /* XXX: must flush on all processor with same address space */
45661382a50Sbellard         tlb_flush_page_write(cpu_single_env, host_start);
45761382a50Sbellard #endif
458fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE
459fd6ce8f6Sbellard         printf("protecting code page: 0x%08lx\n",
460fd6ce8f6Sbellard                host_start);
461fd6ce8f6Sbellard #endif
462fd6ce8f6Sbellard         p->flags &= ~PAGE_WRITE;
463fd6ce8f6Sbellard     }
464fd6ce8f6Sbellard }
465fd6ce8f6Sbellard 
466fd6ce8f6Sbellard /* Allocate a new translation block. Flush the translation buffer if
467fd6ce8f6Sbellard    too many translation blocks or too much generated code. */
468d4e8164fSbellard TranslationBlock *tb_alloc(unsigned long pc)
469fd6ce8f6Sbellard {
470fd6ce8f6Sbellard     TranslationBlock *tb;
471fd6ce8f6Sbellard 
472fd6ce8f6Sbellard     if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
473fd6ce8f6Sbellard         (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
474d4e8164fSbellard         return NULL;
475fd6ce8f6Sbellard     tb = &tbs[nb_tbs++];
476fd6ce8f6Sbellard     tb->pc = pc;
477d4e8164fSbellard     return tb;
478d4e8164fSbellard }
479d4e8164fSbellard 
480d4e8164fSbellard /* link the tb with the other TBs */
481d4e8164fSbellard void tb_link(TranslationBlock *tb)
482d4e8164fSbellard {
483d4e8164fSbellard     unsigned int page_index1, page_index2;
484fd6ce8f6Sbellard 
485fd6ce8f6Sbellard     /* add in the page list */
486d4e8164fSbellard     page_index1 = tb->pc >> TARGET_PAGE_BITS;
487fd6ce8f6Sbellard     tb_alloc_page(tb, page_index1);
488d4e8164fSbellard     page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
489fd6ce8f6Sbellard     if (page_index2 != page_index1) {
490fd6ce8f6Sbellard         tb_alloc_page(tb, page_index2);
491fd6ce8f6Sbellard     }
49261382a50Sbellard #ifdef DEBUG_TB_CHECK
49361382a50Sbellard     tb_page_check();
49461382a50Sbellard #endif
495d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2);
496d4e8164fSbellard     tb->jmp_next[0] = NULL;
497d4e8164fSbellard     tb->jmp_next[1] = NULL;
498d4e8164fSbellard 
499d4e8164fSbellard     /* init original jump addresses */
500d4e8164fSbellard     if (tb->tb_next_offset[0] != 0xffff)
501d4e8164fSbellard         tb_reset_jump(tb, 0);
502d4e8164fSbellard     if (tb->tb_next_offset[1] != 0xffff)
503d4e8164fSbellard         tb_reset_jump(tb, 1);
504fd6ce8f6Sbellard }
505fd6ce8f6Sbellard 
506fd6ce8f6Sbellard /* called from signal handler: invalidate the code and unprotect the
507fd6ce8f6Sbellard    page. Return TRUE if the fault was succesfully handled. */
508fd6ce8f6Sbellard int page_unprotect(unsigned long address)
509fd6ce8f6Sbellard {
5101565b7bcSbellard     unsigned int page_index, prot, pindex;
5111565b7bcSbellard     PageDesc *p, *p1;
512fd6ce8f6Sbellard     unsigned long host_start, host_end, addr;
513fd6ce8f6Sbellard 
5141565b7bcSbellard     host_start = address & host_page_mask;
5151565b7bcSbellard     page_index = host_start >> TARGET_PAGE_BITS;
5161565b7bcSbellard     p1 = page_find(page_index);
5171565b7bcSbellard     if (!p1)
518fd6ce8f6Sbellard         return 0;
5191565b7bcSbellard     host_end = host_start + host_page_size;
5201565b7bcSbellard     p = p1;
5211565b7bcSbellard     prot = 0;
5221565b7bcSbellard     for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
5231565b7bcSbellard         prot |= p->flags;
5241565b7bcSbellard         p++;
5251565b7bcSbellard     }
526fd6ce8f6Sbellard     /* if the page was really writable, then we change its
527fd6ce8f6Sbellard        protection back to writable */
5281565b7bcSbellard     if (prot & PAGE_WRITE_ORG) {
52961382a50Sbellard         pindex = (address - host_start) >> TARGET_PAGE_BITS;
53061382a50Sbellard         if (!(p1[pindex].flags & PAGE_WRITE)) {
53161382a50Sbellard #if !defined(CONFIG_SOFTMMU)
532fd6ce8f6Sbellard             mprotect((void *)host_start, host_page_size,
533fd6ce8f6Sbellard                      (prot & PAGE_BITS) | PAGE_WRITE);
53461382a50Sbellard #endif
5351565b7bcSbellard             p1[pindex].flags |= PAGE_WRITE;
536fd6ce8f6Sbellard             /* and since the content will be modified, we must invalidate
537fd6ce8f6Sbellard                the corresponding translated code. */
538fd6ce8f6Sbellard             tb_invalidate_page(address);
539fd6ce8f6Sbellard #ifdef DEBUG_TB_CHECK
540fd6ce8f6Sbellard             tb_invalidate_check(address);
541fd6ce8f6Sbellard #endif
542fd6ce8f6Sbellard             return 1;
543fd6ce8f6Sbellard         }
544fd6ce8f6Sbellard     }
54561382a50Sbellard     return 0;
54661382a50Sbellard }
547fd6ce8f6Sbellard 
548fd6ce8f6Sbellard /* call this function when system calls directly modify a memory area */
549fd6ce8f6Sbellard void page_unprotect_range(uint8_t *data, unsigned long data_size)
550fd6ce8f6Sbellard {
551fd6ce8f6Sbellard     unsigned long start, end, addr;
552fd6ce8f6Sbellard 
553fd6ce8f6Sbellard     start = (unsigned long)data;
554fd6ce8f6Sbellard     end = start + data_size;
555fd6ce8f6Sbellard     start &= TARGET_PAGE_MASK;
556fd6ce8f6Sbellard     end = TARGET_PAGE_ALIGN(end);
557fd6ce8f6Sbellard     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
558fd6ce8f6Sbellard         page_unprotect(addr);
559fd6ce8f6Sbellard     }
560fd6ce8f6Sbellard }
561a513fe19Sbellard 
562a513fe19Sbellard /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
563a513fe19Sbellard    tb[1].tc_ptr. Return NULL if not found */
564a513fe19Sbellard TranslationBlock *tb_find_pc(unsigned long tc_ptr)
565a513fe19Sbellard {
566a513fe19Sbellard     int m_min, m_max, m;
567a513fe19Sbellard     unsigned long v;
568a513fe19Sbellard     TranslationBlock *tb;
569a513fe19Sbellard 
570a513fe19Sbellard     if (nb_tbs <= 0)
571a513fe19Sbellard         return NULL;
572a513fe19Sbellard     if (tc_ptr < (unsigned long)code_gen_buffer ||
573a513fe19Sbellard         tc_ptr >= (unsigned long)code_gen_ptr)
574a513fe19Sbellard         return NULL;
575a513fe19Sbellard     /* binary search (cf Knuth) */
576a513fe19Sbellard     m_min = 0;
577a513fe19Sbellard     m_max = nb_tbs - 1;
578a513fe19Sbellard     while (m_min <= m_max) {
579a513fe19Sbellard         m = (m_min + m_max) >> 1;
580a513fe19Sbellard         tb = &tbs[m];
581a513fe19Sbellard         v = (unsigned long)tb->tc_ptr;
582a513fe19Sbellard         if (v == tc_ptr)
583a513fe19Sbellard             return tb;
584a513fe19Sbellard         else if (tc_ptr < v) {
585a513fe19Sbellard             m_max = m - 1;
586a513fe19Sbellard         } else {
587a513fe19Sbellard             m_min = m + 1;
588a513fe19Sbellard         }
589a513fe19Sbellard     }
590a513fe19Sbellard     return &tbs[m_max];
591a513fe19Sbellard }
5927501267eSbellard 
593ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb);
594ea041c0eSbellard 
595ea041c0eSbellard static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
596ea041c0eSbellard {
597ea041c0eSbellard     TranslationBlock *tb1, *tb_next, **ptb;
598ea041c0eSbellard     unsigned int n1;
599ea041c0eSbellard 
600ea041c0eSbellard     tb1 = tb->jmp_next[n];
601ea041c0eSbellard     if (tb1 != NULL) {
602ea041c0eSbellard         /* find head of list */
603ea041c0eSbellard         for(;;) {
604ea041c0eSbellard             n1 = (long)tb1 & 3;
605ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
606ea041c0eSbellard             if (n1 == 2)
607ea041c0eSbellard                 break;
608ea041c0eSbellard             tb1 = tb1->jmp_next[n1];
609ea041c0eSbellard         }
610ea041c0eSbellard         /* we are now sure now that tb jumps to tb1 */
611ea041c0eSbellard         tb_next = tb1;
612ea041c0eSbellard 
613ea041c0eSbellard         /* remove tb from the jmp_first list */
614ea041c0eSbellard         ptb = &tb_next->jmp_first;
615ea041c0eSbellard         for(;;) {
616ea041c0eSbellard             tb1 = *ptb;
617ea041c0eSbellard             n1 = (long)tb1 & 3;
618ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
619ea041c0eSbellard             if (n1 == n && tb1 == tb)
620ea041c0eSbellard                 break;
621ea041c0eSbellard             ptb = &tb1->jmp_next[n1];
622ea041c0eSbellard         }
623ea041c0eSbellard         *ptb = tb->jmp_next[n];
624ea041c0eSbellard         tb->jmp_next[n] = NULL;
625ea041c0eSbellard 
626ea041c0eSbellard         /* suppress the jump to next tb in generated code */
627ea041c0eSbellard         tb_reset_jump(tb, n);
628ea041c0eSbellard 
629ea041c0eSbellard         /* suppress jumps in the tb on which we could have jump */
630ea041c0eSbellard         tb_reset_jump_recursive(tb_next);
631ea041c0eSbellard     }
632ea041c0eSbellard }
633ea041c0eSbellard 
634ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb)
635ea041c0eSbellard {
636ea041c0eSbellard     tb_reset_jump_recursive2(tb, 0);
637ea041c0eSbellard     tb_reset_jump_recursive2(tb, 1);
638ea041c0eSbellard }
639ea041c0eSbellard 
640c33a346eSbellard /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
641c33a346eSbellard    breakpoint is reached */
6424c3a88a2Sbellard int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
6434c3a88a2Sbellard {
6444c3a88a2Sbellard #if defined(TARGET_I386)
6454c3a88a2Sbellard     int i;
6464c3a88a2Sbellard 
6474c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
6484c3a88a2Sbellard         if (env->breakpoints[i] == pc)
6494c3a88a2Sbellard             return 0;
6504c3a88a2Sbellard     }
6514c3a88a2Sbellard 
6524c3a88a2Sbellard     if (env->nb_breakpoints >= MAX_BREAKPOINTS)
6534c3a88a2Sbellard         return -1;
6544c3a88a2Sbellard     env->breakpoints[env->nb_breakpoints++] = pc;
6554c3a88a2Sbellard     tb_invalidate_page(pc);
6564c3a88a2Sbellard     return 0;
6574c3a88a2Sbellard #else
6584c3a88a2Sbellard     return -1;
6594c3a88a2Sbellard #endif
6604c3a88a2Sbellard }
6614c3a88a2Sbellard 
6624c3a88a2Sbellard /* remove a breakpoint */
6634c3a88a2Sbellard int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
6644c3a88a2Sbellard {
6654c3a88a2Sbellard #if defined(TARGET_I386)
6664c3a88a2Sbellard     int i;
6674c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
6684c3a88a2Sbellard         if (env->breakpoints[i] == pc)
6694c3a88a2Sbellard             goto found;
6704c3a88a2Sbellard     }
6714c3a88a2Sbellard     return -1;
6724c3a88a2Sbellard  found:
6734c3a88a2Sbellard     memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
6744c3a88a2Sbellard             (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
6754c3a88a2Sbellard     env->nb_breakpoints--;
6764c3a88a2Sbellard     tb_invalidate_page(pc);
6774c3a88a2Sbellard     return 0;
6784c3a88a2Sbellard #else
6794c3a88a2Sbellard     return -1;
6804c3a88a2Sbellard #endif
6814c3a88a2Sbellard }
6824c3a88a2Sbellard 
683c33a346eSbellard /* enable or disable single step mode. EXCP_DEBUG is returned by the
684c33a346eSbellard    CPU loop after each instruction */
685c33a346eSbellard void cpu_single_step(CPUState *env, int enabled)
686c33a346eSbellard {
687c33a346eSbellard #if defined(TARGET_I386)
688c33a346eSbellard     if (env->singlestep_enabled != enabled) {
689c33a346eSbellard         env->singlestep_enabled = enabled;
690c33a346eSbellard         /* must flush all the translated code to avoid inconsistancies */
691c33a346eSbellard         tb_flush();
692c33a346eSbellard     }
693c33a346eSbellard #endif
694c33a346eSbellard }
695c33a346eSbellard 
69634865134Sbellard /* enable or disable low levels log */
69734865134Sbellard void cpu_set_log(int log_flags)
69834865134Sbellard {
69934865134Sbellard     loglevel = log_flags;
70034865134Sbellard     if (loglevel && !logfile) {
70134865134Sbellard         logfile = fopen(logfilename, "w");
70234865134Sbellard         if (!logfile) {
70334865134Sbellard             perror(logfilename);
70434865134Sbellard             _exit(1);
70534865134Sbellard         }
70634865134Sbellard         setvbuf(logfile, NULL, _IOLBF, 0);
70734865134Sbellard     }
70834865134Sbellard }
70934865134Sbellard 
71034865134Sbellard void cpu_set_log_filename(const char *filename)
71134865134Sbellard {
71234865134Sbellard     logfilename = strdup(filename);
71334865134Sbellard }
714c33a346eSbellard 
71568a79315Sbellard /* mask must never be zero */
71668a79315Sbellard void cpu_interrupt(CPUState *env, int mask)
717ea041c0eSbellard {
718ea041c0eSbellard     TranslationBlock *tb;
719ea041c0eSbellard 
72068a79315Sbellard     env->interrupt_request |= mask;
721ea041c0eSbellard     /* if the cpu is currently executing code, we must unlink it and
722ea041c0eSbellard        all the potentially executing TB */
723ea041c0eSbellard     tb = env->current_tb;
724ea041c0eSbellard     if (tb) {
725ea041c0eSbellard         tb_reset_jump_recursive(tb);
726ea041c0eSbellard     }
727ea041c0eSbellard }
728ea041c0eSbellard 
729ea041c0eSbellard 
7307501267eSbellard void cpu_abort(CPUState *env, const char *fmt, ...)
7317501267eSbellard {
7327501267eSbellard     va_list ap;
7337501267eSbellard 
7347501267eSbellard     va_start(ap, fmt);
7357501267eSbellard     fprintf(stderr, "qemu: fatal: ");
7367501267eSbellard     vfprintf(stderr, fmt, ap);
7377501267eSbellard     fprintf(stderr, "\n");
7387501267eSbellard #ifdef TARGET_I386
7397501267eSbellard     cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
7407501267eSbellard #endif
7417501267eSbellard     va_end(ap);
7427501267eSbellard     abort();
7437501267eSbellard }
7447501267eSbellard 
74566e85a21Sbellard #ifdef TARGET_I386
74666e85a21Sbellard /* unmap all maped pages and flush all associated code */
74766e85a21Sbellard void page_unmap(void)
74866e85a21Sbellard {
74961382a50Sbellard     PageDesc *pmap;
75061382a50Sbellard     int i;
75166e85a21Sbellard 
75266e85a21Sbellard     for(i = 0; i < L1_SIZE; i++) {
75366e85a21Sbellard         pmap = l1_map[i];
75466e85a21Sbellard         if (pmap) {
75561382a50Sbellard #if !defined(CONFIG_SOFTMMU)
75661382a50Sbellard             PageDesc *p;
75761382a50Sbellard             unsigned long addr;
75861382a50Sbellard             int j, ret, j1;
75961382a50Sbellard 
76066e85a21Sbellard             p = pmap;
7617c2d6a78Sbellard             for(j = 0;j < L2_SIZE;) {
76266e85a21Sbellard                 if (p->flags & PAGE_VALID) {
76366e85a21Sbellard                     addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
7647c2d6a78Sbellard                     /* we try to find a range to make less syscalls */
7657c2d6a78Sbellard                     j1 = j;
7667c2d6a78Sbellard                     p++;
7677c2d6a78Sbellard                     j++;
7687c2d6a78Sbellard                     while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
7697c2d6a78Sbellard                         p++;
7707c2d6a78Sbellard                         j++;
7717c2d6a78Sbellard                     }
7727c2d6a78Sbellard                     ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
77366e85a21Sbellard                     if (ret != 0) {
77466e85a21Sbellard                         fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
77566e85a21Sbellard                         exit(1);
77666e85a21Sbellard                     }
7777c2d6a78Sbellard                 } else {
77866e85a21Sbellard                     p++;
7797c2d6a78Sbellard                     j++;
7807c2d6a78Sbellard                 }
78166e85a21Sbellard             }
78261382a50Sbellard #endif
78366e85a21Sbellard             free(pmap);
78466e85a21Sbellard             l1_map[i] = NULL;
78566e85a21Sbellard         }
78666e85a21Sbellard     }
78766e85a21Sbellard     tb_flush();
78866e85a21Sbellard }
78966e85a21Sbellard #endif
79033417e70Sbellard 
79133417e70Sbellard void tlb_flush(CPUState *env)
79233417e70Sbellard {
79361382a50Sbellard #if !defined(CONFIG_USER_ONLY)
79433417e70Sbellard     int i;
79533417e70Sbellard     for(i = 0; i < CPU_TLB_SIZE; i++) {
79633417e70Sbellard         env->tlb_read[0][i].address = -1;
79733417e70Sbellard         env->tlb_write[0][i].address = -1;
79833417e70Sbellard         env->tlb_read[1][i].address = -1;
79933417e70Sbellard         env->tlb_write[1][i].address = -1;
80033417e70Sbellard     }
80133417e70Sbellard #endif
80233417e70Sbellard }
80333417e70Sbellard 
80461382a50Sbellard static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
80561382a50Sbellard {
80661382a50Sbellard     if (addr == (tlb_entry->address &
80761382a50Sbellard                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
80861382a50Sbellard         tlb_entry->address = -1;
80961382a50Sbellard }
81061382a50Sbellard 
81133417e70Sbellard void tlb_flush_page(CPUState *env, uint32_t addr)
81233417e70Sbellard {
81361382a50Sbellard #if !defined(CONFIG_USER_ONLY)
81433417e70Sbellard     int i;
81533417e70Sbellard 
81661382a50Sbellard     addr &= TARGET_PAGE_MASK;
81733417e70Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
81861382a50Sbellard     tlb_flush_entry(&env->tlb_read[0][i], addr);
81961382a50Sbellard     tlb_flush_entry(&env->tlb_write[0][i], addr);
82061382a50Sbellard     tlb_flush_entry(&env->tlb_read[1][i], addr);
82161382a50Sbellard     tlb_flush_entry(&env->tlb_write[1][i], addr);
82261382a50Sbellard #endif
82361382a50Sbellard }
82461382a50Sbellard 
82561382a50Sbellard /* make all write to page 'addr' trigger a TLB exception to detect
82661382a50Sbellard    self modifying code */
82761382a50Sbellard void tlb_flush_page_write(CPUState *env, uint32_t addr)
82861382a50Sbellard {
82961382a50Sbellard #if !defined(CONFIG_USER_ONLY)
83061382a50Sbellard     int i;
83161382a50Sbellard 
83261382a50Sbellard     addr &= TARGET_PAGE_MASK;
83361382a50Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
83461382a50Sbellard     tlb_flush_entry(&env->tlb_write[0][i], addr);
83561382a50Sbellard     tlb_flush_entry(&env->tlb_write[1][i], addr);
83633417e70Sbellard #endif
83733417e70Sbellard }
83833417e70Sbellard 
83933417e70Sbellard static inline unsigned long *physpage_find_alloc(unsigned int page)
84033417e70Sbellard {
84133417e70Sbellard     unsigned long **lp, *p;
84233417e70Sbellard     unsigned int index, i;
84333417e70Sbellard 
84433417e70Sbellard     index = page >> TARGET_PAGE_BITS;
84533417e70Sbellard     lp = &l1_physmap[index >> L2_BITS];
84633417e70Sbellard     p = *lp;
84733417e70Sbellard     if (!p) {
84833417e70Sbellard         /* allocate if not found */
84933417e70Sbellard         p = malloc(sizeof(unsigned long) * L2_SIZE);
85033417e70Sbellard         for(i = 0; i < L2_SIZE; i++)
85133417e70Sbellard             p[i] = IO_MEM_UNASSIGNED;
85233417e70Sbellard         *lp = p;
85333417e70Sbellard     }
85433417e70Sbellard     return p + (index & (L2_SIZE - 1));
85533417e70Sbellard }
85633417e70Sbellard 
85733417e70Sbellard /* return NULL if no page defined (unused memory) */
85833417e70Sbellard unsigned long physpage_find(unsigned long page)
85933417e70Sbellard {
86033417e70Sbellard     unsigned long *p;
86133417e70Sbellard     unsigned int index;
86233417e70Sbellard     index = page >> TARGET_PAGE_BITS;
86333417e70Sbellard     p = l1_physmap[index >> L2_BITS];
86433417e70Sbellard     if (!p)
86533417e70Sbellard         return IO_MEM_UNASSIGNED;
86633417e70Sbellard     return p[index & (L2_SIZE - 1)];
86733417e70Sbellard }
86833417e70Sbellard 
86933417e70Sbellard /* register physical memory. 'size' must be a multiple of the target
87033417e70Sbellard    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
87133417e70Sbellard    io memory page */
87233417e70Sbellard void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
87333417e70Sbellard                                   long phys_offset)
87433417e70Sbellard {
87533417e70Sbellard     unsigned long addr, end_addr;
87633417e70Sbellard     unsigned long *p;
87733417e70Sbellard 
87833417e70Sbellard     end_addr = start_addr + size;
87933417e70Sbellard     for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
88033417e70Sbellard         p = physpage_find_alloc(addr);
88133417e70Sbellard         *p = phys_offset;
88233417e70Sbellard         if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
88333417e70Sbellard             phys_offset += TARGET_PAGE_SIZE;
88433417e70Sbellard     }
88533417e70Sbellard }
88633417e70Sbellard 
88733417e70Sbellard static uint32_t unassigned_mem_readb(uint32_t addr)
88833417e70Sbellard {
88933417e70Sbellard     return 0;
89033417e70Sbellard }
89133417e70Sbellard 
89233417e70Sbellard static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
89333417e70Sbellard {
89433417e70Sbellard }
89533417e70Sbellard 
89633417e70Sbellard static CPUReadMemoryFunc *unassigned_mem_read[3] = {
89733417e70Sbellard     unassigned_mem_readb,
89833417e70Sbellard     unassigned_mem_readb,
89933417e70Sbellard     unassigned_mem_readb,
90033417e70Sbellard };
90133417e70Sbellard 
90233417e70Sbellard static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
90333417e70Sbellard     unassigned_mem_writeb,
90433417e70Sbellard     unassigned_mem_writeb,
90533417e70Sbellard     unassigned_mem_writeb,
90633417e70Sbellard };
90733417e70Sbellard 
90833417e70Sbellard 
90933417e70Sbellard static void io_mem_init(void)
91033417e70Sbellard {
91133417e70Sbellard     io_mem_nb = 1;
91233417e70Sbellard     cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
91333417e70Sbellard }
91433417e70Sbellard 
91533417e70Sbellard /* mem_read and mem_write are arrays of functions containing the
91633417e70Sbellard    function to access byte (index 0), word (index 1) and dword (index
91733417e70Sbellard    2). All functions must be supplied. If io_index is non zero, the
91833417e70Sbellard    corresponding io zone is modified. If it is zero, a new io zone is
91933417e70Sbellard    allocated. The return value can be used with
92033417e70Sbellard    cpu_register_physical_memory(). (-1) is returned if error. */
92133417e70Sbellard int cpu_register_io_memory(int io_index,
92233417e70Sbellard                            CPUReadMemoryFunc **mem_read,
92333417e70Sbellard                            CPUWriteMemoryFunc **mem_write)
92433417e70Sbellard {
92533417e70Sbellard     int i;
92633417e70Sbellard 
92733417e70Sbellard     if (io_index <= 0) {
92833417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
92933417e70Sbellard             return -1;
93033417e70Sbellard         io_index = io_mem_nb++;
93133417e70Sbellard     } else {
93233417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
93333417e70Sbellard             return -1;
93433417e70Sbellard     }
93533417e70Sbellard 
93633417e70Sbellard     for(i = 0;i < 3; i++) {
93733417e70Sbellard         io_mem_read[io_index][i] = mem_read[i];
93833417e70Sbellard         io_mem_write[io_index][i] = mem_write[i];
93933417e70Sbellard     }
94033417e70Sbellard     return io_index << IO_MEM_SHIFT;
94133417e70Sbellard }
94261382a50Sbellard 
94361382a50Sbellard #if !defined(CONFIG_USER_ONLY)
94461382a50Sbellard 
94561382a50Sbellard #define MMUSUFFIX _cmmu
94661382a50Sbellard #define GETPC() NULL
94761382a50Sbellard #define env cpu_single_env
94861382a50Sbellard 
94961382a50Sbellard #define SHIFT 0
95061382a50Sbellard #include "softmmu_template.h"
95161382a50Sbellard 
95261382a50Sbellard #define SHIFT 1
95361382a50Sbellard #include "softmmu_template.h"
95461382a50Sbellard 
95561382a50Sbellard #define SHIFT 2
95661382a50Sbellard #include "softmmu_template.h"
95761382a50Sbellard 
95861382a50Sbellard #define SHIFT 3
95961382a50Sbellard #include "softmmu_template.h"
96061382a50Sbellard 
96161382a50Sbellard #undef env
96261382a50Sbellard 
96361382a50Sbellard #endif
964