xref: /qemu/system/physmem.c (revision 61382a500a9e54ef96ca28e0f221151f569cbb6e)
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 
365fd6ce8f6Sbellard     /* remove the TB from the hash list */
366fd6ce8f6Sbellard     h = tb_hash_func(tb->pc);
367fd6ce8f6Sbellard     tb_remove(&tb_hash[h], tb,
368fd6ce8f6Sbellard               offsetof(TranslationBlock, hash_next));
369fd6ce8f6Sbellard     /* remove the TB from the page list */
370fd6ce8f6Sbellard     page_index1 = tb->pc >> TARGET_PAGE_BITS;
371fd6ce8f6Sbellard     if ((page_index1 & 1) == parity) {
372fd6ce8f6Sbellard         p = page_find(page_index1);
373fd6ce8f6Sbellard         tb_remove(&p->first_tb, tb,
374fd6ce8f6Sbellard                   offsetof(TranslationBlock, page_next[page_index1 & 1]));
375fd6ce8f6Sbellard     }
376fd6ce8f6Sbellard     page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
377fd6ce8f6Sbellard     if ((page_index2 & 1) == parity) {
378fd6ce8f6Sbellard         p = page_find(page_index2);
379fd6ce8f6Sbellard         tb_remove(&p->first_tb, tb,
380fd6ce8f6Sbellard                   offsetof(TranslationBlock, page_next[page_index2 & 1]));
381fd6ce8f6Sbellard     }
382d4e8164fSbellard 
383d4e8164fSbellard     /* suppress this TB from the two jump lists */
384d4e8164fSbellard     tb_jmp_remove(tb, 0);
385d4e8164fSbellard     tb_jmp_remove(tb, 1);
386d4e8164fSbellard 
387d4e8164fSbellard     /* suppress any remaining jumps to this TB */
388d4e8164fSbellard     tb1 = tb->jmp_first;
389d4e8164fSbellard     for(;;) {
390d4e8164fSbellard         n1 = (long)tb1 & 3;
391d4e8164fSbellard         if (n1 == 2)
392d4e8164fSbellard             break;
393d4e8164fSbellard         tb1 = (TranslationBlock *)((long)tb1 & ~3);
394d4e8164fSbellard         tb2 = tb1->jmp_next[n1];
395d4e8164fSbellard         tb_reset_jump(tb1, n1);
396d4e8164fSbellard         tb1->jmp_next[n1] = NULL;
397d4e8164fSbellard         tb1 = tb2;
398d4e8164fSbellard     }
399d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
400fd6ce8f6Sbellard }
401fd6ce8f6Sbellard 
402fd6ce8f6Sbellard /* invalidate all TBs which intersect with the target page starting at addr */
403fd6ce8f6Sbellard static void tb_invalidate_page(unsigned long address)
404fd6ce8f6Sbellard {
405fd6ce8f6Sbellard     TranslationBlock *tb_next, *tb;
406fd6ce8f6Sbellard     unsigned int page_index;
407fd6ce8f6Sbellard     int parity1, parity2;
408fd6ce8f6Sbellard     PageDesc *p;
409fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE
410fd6ce8f6Sbellard     printf("tb_invalidate_page: %lx\n", address);
411fd6ce8f6Sbellard #endif
412fd6ce8f6Sbellard 
413fd6ce8f6Sbellard     page_index = address >> TARGET_PAGE_BITS;
414fd6ce8f6Sbellard     p = page_find(page_index);
415fd6ce8f6Sbellard     if (!p)
416fd6ce8f6Sbellard         return;
417fd6ce8f6Sbellard     tb = p->first_tb;
418fd6ce8f6Sbellard     parity1 = page_index & 1;
419fd6ce8f6Sbellard     parity2 = parity1 ^ 1;
420fd6ce8f6Sbellard     while (tb != NULL) {
421fd6ce8f6Sbellard         tb_next = tb->page_next[parity1];
422fd6ce8f6Sbellard         tb_invalidate(tb, parity2);
423fd6ce8f6Sbellard         tb = tb_next;
424fd6ce8f6Sbellard     }
425fd6ce8f6Sbellard     p->first_tb = NULL;
426fd6ce8f6Sbellard }
427fd6ce8f6Sbellard 
428fd6ce8f6Sbellard /* add the tb in the target page and protect it if necessary */
429fd6ce8f6Sbellard static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
430fd6ce8f6Sbellard {
431fd6ce8f6Sbellard     PageDesc *p;
432fd6ce8f6Sbellard     unsigned long host_start, host_end, addr, page_addr;
433fd6ce8f6Sbellard     int prot;
434fd6ce8f6Sbellard 
435fd6ce8f6Sbellard     p = page_find_alloc(page_index);
436fd6ce8f6Sbellard     tb->page_next[page_index & 1] = p->first_tb;
437fd6ce8f6Sbellard     p->first_tb = tb;
438fd6ce8f6Sbellard     if (p->flags & PAGE_WRITE) {
439fd6ce8f6Sbellard         /* force the host page as non writable (writes will have a
440fd6ce8f6Sbellard            page fault + mprotect overhead) */
441fd6ce8f6Sbellard         page_addr = (page_index << TARGET_PAGE_BITS);
442fd6ce8f6Sbellard         host_start = page_addr & host_page_mask;
443fd6ce8f6Sbellard         host_end = host_start + host_page_size;
444fd6ce8f6Sbellard         prot = 0;
445fd6ce8f6Sbellard         for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
446fd6ce8f6Sbellard             prot |= page_get_flags(addr);
44761382a50Sbellard #if !defined(CONFIG_SOFTMMU)
448fd6ce8f6Sbellard         mprotect((void *)host_start, host_page_size,
449fd6ce8f6Sbellard                  (prot & PAGE_BITS) & ~PAGE_WRITE);
45061382a50Sbellard #endif
45161382a50Sbellard #if !defined(CONFIG_USER_ONLY)
45261382a50Sbellard         /* suppress soft TLB */
45361382a50Sbellard         /* XXX: must flush on all processor with same address space */
45461382a50Sbellard         tlb_flush_page_write(cpu_single_env, host_start);
45561382a50Sbellard #endif
456fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE
457fd6ce8f6Sbellard         printf("protecting code page: 0x%08lx\n",
458fd6ce8f6Sbellard                host_start);
459fd6ce8f6Sbellard #endif
460fd6ce8f6Sbellard         p->flags &= ~PAGE_WRITE;
461fd6ce8f6Sbellard     }
462fd6ce8f6Sbellard }
463fd6ce8f6Sbellard 
464fd6ce8f6Sbellard /* Allocate a new translation block. Flush the translation buffer if
465fd6ce8f6Sbellard    too many translation blocks or too much generated code. */
466d4e8164fSbellard TranslationBlock *tb_alloc(unsigned long pc)
467fd6ce8f6Sbellard {
468fd6ce8f6Sbellard     TranslationBlock *tb;
469fd6ce8f6Sbellard 
470fd6ce8f6Sbellard     if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
471fd6ce8f6Sbellard         (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
472d4e8164fSbellard         return NULL;
473fd6ce8f6Sbellard     tb = &tbs[nb_tbs++];
474fd6ce8f6Sbellard     tb->pc = pc;
475d4e8164fSbellard     return tb;
476d4e8164fSbellard }
477d4e8164fSbellard 
478d4e8164fSbellard /* link the tb with the other TBs */
479d4e8164fSbellard void tb_link(TranslationBlock *tb)
480d4e8164fSbellard {
481d4e8164fSbellard     unsigned int page_index1, page_index2;
482fd6ce8f6Sbellard 
483fd6ce8f6Sbellard     /* add in the page list */
484d4e8164fSbellard     page_index1 = tb->pc >> TARGET_PAGE_BITS;
485fd6ce8f6Sbellard     tb_alloc_page(tb, page_index1);
486d4e8164fSbellard     page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
487fd6ce8f6Sbellard     if (page_index2 != page_index1) {
488fd6ce8f6Sbellard         tb_alloc_page(tb, page_index2);
489fd6ce8f6Sbellard     }
49061382a50Sbellard #ifdef DEBUG_TB_CHECK
49161382a50Sbellard     tb_page_check();
49261382a50Sbellard #endif
493d4e8164fSbellard     tb->jmp_first = (TranslationBlock *)((long)tb | 2);
494d4e8164fSbellard     tb->jmp_next[0] = NULL;
495d4e8164fSbellard     tb->jmp_next[1] = NULL;
496d4e8164fSbellard 
497d4e8164fSbellard     /* init original jump addresses */
498d4e8164fSbellard     if (tb->tb_next_offset[0] != 0xffff)
499d4e8164fSbellard         tb_reset_jump(tb, 0);
500d4e8164fSbellard     if (tb->tb_next_offset[1] != 0xffff)
501d4e8164fSbellard         tb_reset_jump(tb, 1);
502fd6ce8f6Sbellard }
503fd6ce8f6Sbellard 
504fd6ce8f6Sbellard /* called from signal handler: invalidate the code and unprotect the
505fd6ce8f6Sbellard    page. Return TRUE if the fault was succesfully handled. */
506fd6ce8f6Sbellard int page_unprotect(unsigned long address)
507fd6ce8f6Sbellard {
5081565b7bcSbellard     unsigned int page_index, prot, pindex;
5091565b7bcSbellard     PageDesc *p, *p1;
510fd6ce8f6Sbellard     unsigned long host_start, host_end, addr;
511fd6ce8f6Sbellard 
5121565b7bcSbellard     host_start = address & host_page_mask;
5131565b7bcSbellard     page_index = host_start >> TARGET_PAGE_BITS;
5141565b7bcSbellard     p1 = page_find(page_index);
5151565b7bcSbellard     if (!p1)
516fd6ce8f6Sbellard         return 0;
5171565b7bcSbellard     host_end = host_start + host_page_size;
5181565b7bcSbellard     p = p1;
5191565b7bcSbellard     prot = 0;
5201565b7bcSbellard     for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
5211565b7bcSbellard         prot |= p->flags;
5221565b7bcSbellard         p++;
5231565b7bcSbellard     }
524fd6ce8f6Sbellard     /* if the page was really writable, then we change its
525fd6ce8f6Sbellard        protection back to writable */
5261565b7bcSbellard     if (prot & PAGE_WRITE_ORG) {
52761382a50Sbellard         pindex = (address - host_start) >> TARGET_PAGE_BITS;
52861382a50Sbellard         if (!(p1[pindex].flags & PAGE_WRITE)) {
52961382a50Sbellard #if !defined(CONFIG_SOFTMMU)
530fd6ce8f6Sbellard             mprotect((void *)host_start, host_page_size,
531fd6ce8f6Sbellard                      (prot & PAGE_BITS) | PAGE_WRITE);
53261382a50Sbellard #endif
5331565b7bcSbellard             p1[pindex].flags |= PAGE_WRITE;
534fd6ce8f6Sbellard             /* and since the content will be modified, we must invalidate
535fd6ce8f6Sbellard                the corresponding translated code. */
536fd6ce8f6Sbellard             tb_invalidate_page(address);
537fd6ce8f6Sbellard #ifdef DEBUG_TB_CHECK
538fd6ce8f6Sbellard             tb_invalidate_check(address);
539fd6ce8f6Sbellard #endif
540fd6ce8f6Sbellard             return 1;
541fd6ce8f6Sbellard         }
542fd6ce8f6Sbellard     }
54361382a50Sbellard     return 0;
54461382a50Sbellard }
545fd6ce8f6Sbellard 
546fd6ce8f6Sbellard /* call this function when system calls directly modify a memory area */
547fd6ce8f6Sbellard void page_unprotect_range(uint8_t *data, unsigned long data_size)
548fd6ce8f6Sbellard {
549fd6ce8f6Sbellard     unsigned long start, end, addr;
550fd6ce8f6Sbellard 
551fd6ce8f6Sbellard     start = (unsigned long)data;
552fd6ce8f6Sbellard     end = start + data_size;
553fd6ce8f6Sbellard     start &= TARGET_PAGE_MASK;
554fd6ce8f6Sbellard     end = TARGET_PAGE_ALIGN(end);
555fd6ce8f6Sbellard     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
556fd6ce8f6Sbellard         page_unprotect(addr);
557fd6ce8f6Sbellard     }
558fd6ce8f6Sbellard }
559a513fe19Sbellard 
560a513fe19Sbellard /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
561a513fe19Sbellard    tb[1].tc_ptr. Return NULL if not found */
562a513fe19Sbellard TranslationBlock *tb_find_pc(unsigned long tc_ptr)
563a513fe19Sbellard {
564a513fe19Sbellard     int m_min, m_max, m;
565a513fe19Sbellard     unsigned long v;
566a513fe19Sbellard     TranslationBlock *tb;
567a513fe19Sbellard 
568a513fe19Sbellard     if (nb_tbs <= 0)
569a513fe19Sbellard         return NULL;
570a513fe19Sbellard     if (tc_ptr < (unsigned long)code_gen_buffer ||
571a513fe19Sbellard         tc_ptr >= (unsigned long)code_gen_ptr)
572a513fe19Sbellard         return NULL;
573a513fe19Sbellard     /* binary search (cf Knuth) */
574a513fe19Sbellard     m_min = 0;
575a513fe19Sbellard     m_max = nb_tbs - 1;
576a513fe19Sbellard     while (m_min <= m_max) {
577a513fe19Sbellard         m = (m_min + m_max) >> 1;
578a513fe19Sbellard         tb = &tbs[m];
579a513fe19Sbellard         v = (unsigned long)tb->tc_ptr;
580a513fe19Sbellard         if (v == tc_ptr)
581a513fe19Sbellard             return tb;
582a513fe19Sbellard         else if (tc_ptr < v) {
583a513fe19Sbellard             m_max = m - 1;
584a513fe19Sbellard         } else {
585a513fe19Sbellard             m_min = m + 1;
586a513fe19Sbellard         }
587a513fe19Sbellard     }
588a513fe19Sbellard     return &tbs[m_max];
589a513fe19Sbellard }
5907501267eSbellard 
591ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb);
592ea041c0eSbellard 
593ea041c0eSbellard static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
594ea041c0eSbellard {
595ea041c0eSbellard     TranslationBlock *tb1, *tb_next, **ptb;
596ea041c0eSbellard     unsigned int n1;
597ea041c0eSbellard 
598ea041c0eSbellard     tb1 = tb->jmp_next[n];
599ea041c0eSbellard     if (tb1 != NULL) {
600ea041c0eSbellard         /* find head of list */
601ea041c0eSbellard         for(;;) {
602ea041c0eSbellard             n1 = (long)tb1 & 3;
603ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
604ea041c0eSbellard             if (n1 == 2)
605ea041c0eSbellard                 break;
606ea041c0eSbellard             tb1 = tb1->jmp_next[n1];
607ea041c0eSbellard         }
608ea041c0eSbellard         /* we are now sure now that tb jumps to tb1 */
609ea041c0eSbellard         tb_next = tb1;
610ea041c0eSbellard 
611ea041c0eSbellard         /* remove tb from the jmp_first list */
612ea041c0eSbellard         ptb = &tb_next->jmp_first;
613ea041c0eSbellard         for(;;) {
614ea041c0eSbellard             tb1 = *ptb;
615ea041c0eSbellard             n1 = (long)tb1 & 3;
616ea041c0eSbellard             tb1 = (TranslationBlock *)((long)tb1 & ~3);
617ea041c0eSbellard             if (n1 == n && tb1 == tb)
618ea041c0eSbellard                 break;
619ea041c0eSbellard             ptb = &tb1->jmp_next[n1];
620ea041c0eSbellard         }
621ea041c0eSbellard         *ptb = tb->jmp_next[n];
622ea041c0eSbellard         tb->jmp_next[n] = NULL;
623ea041c0eSbellard 
624ea041c0eSbellard         /* suppress the jump to next tb in generated code */
625ea041c0eSbellard         tb_reset_jump(tb, n);
626ea041c0eSbellard 
627ea041c0eSbellard         /* suppress jumps in the tb on which we could have jump */
628ea041c0eSbellard         tb_reset_jump_recursive(tb_next);
629ea041c0eSbellard     }
630ea041c0eSbellard }
631ea041c0eSbellard 
632ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb)
633ea041c0eSbellard {
634ea041c0eSbellard     tb_reset_jump_recursive2(tb, 0);
635ea041c0eSbellard     tb_reset_jump_recursive2(tb, 1);
636ea041c0eSbellard }
637ea041c0eSbellard 
638c33a346eSbellard /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
639c33a346eSbellard    breakpoint is reached */
6404c3a88a2Sbellard int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
6414c3a88a2Sbellard {
6424c3a88a2Sbellard #if defined(TARGET_I386)
6434c3a88a2Sbellard     int i;
6444c3a88a2Sbellard 
6454c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
6464c3a88a2Sbellard         if (env->breakpoints[i] == pc)
6474c3a88a2Sbellard             return 0;
6484c3a88a2Sbellard     }
6494c3a88a2Sbellard 
6504c3a88a2Sbellard     if (env->nb_breakpoints >= MAX_BREAKPOINTS)
6514c3a88a2Sbellard         return -1;
6524c3a88a2Sbellard     env->breakpoints[env->nb_breakpoints++] = pc;
6534c3a88a2Sbellard     tb_invalidate_page(pc);
6544c3a88a2Sbellard     return 0;
6554c3a88a2Sbellard #else
6564c3a88a2Sbellard     return -1;
6574c3a88a2Sbellard #endif
6584c3a88a2Sbellard }
6594c3a88a2Sbellard 
6604c3a88a2Sbellard /* remove a breakpoint */
6614c3a88a2Sbellard int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
6624c3a88a2Sbellard {
6634c3a88a2Sbellard #if defined(TARGET_I386)
6644c3a88a2Sbellard     int i;
6654c3a88a2Sbellard     for(i = 0; i < env->nb_breakpoints; i++) {
6664c3a88a2Sbellard         if (env->breakpoints[i] == pc)
6674c3a88a2Sbellard             goto found;
6684c3a88a2Sbellard     }
6694c3a88a2Sbellard     return -1;
6704c3a88a2Sbellard  found:
6714c3a88a2Sbellard     memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
6724c3a88a2Sbellard             (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
6734c3a88a2Sbellard     env->nb_breakpoints--;
6744c3a88a2Sbellard     tb_invalidate_page(pc);
6754c3a88a2Sbellard     return 0;
6764c3a88a2Sbellard #else
6774c3a88a2Sbellard     return -1;
6784c3a88a2Sbellard #endif
6794c3a88a2Sbellard }
6804c3a88a2Sbellard 
681c33a346eSbellard /* enable or disable single step mode. EXCP_DEBUG is returned by the
682c33a346eSbellard    CPU loop after each instruction */
683c33a346eSbellard void cpu_single_step(CPUState *env, int enabled)
684c33a346eSbellard {
685c33a346eSbellard #if defined(TARGET_I386)
686c33a346eSbellard     if (env->singlestep_enabled != enabled) {
687c33a346eSbellard         env->singlestep_enabled = enabled;
688c33a346eSbellard         /* must flush all the translated code to avoid inconsistancies */
689c33a346eSbellard         tb_flush();
690c33a346eSbellard     }
691c33a346eSbellard #endif
692c33a346eSbellard }
693c33a346eSbellard 
69434865134Sbellard /* enable or disable low levels log */
69534865134Sbellard void cpu_set_log(int log_flags)
69634865134Sbellard {
69734865134Sbellard     loglevel = log_flags;
69834865134Sbellard     if (loglevel && !logfile) {
69934865134Sbellard         logfile = fopen(logfilename, "w");
70034865134Sbellard         if (!logfile) {
70134865134Sbellard             perror(logfilename);
70234865134Sbellard             _exit(1);
70334865134Sbellard         }
70434865134Sbellard         setvbuf(logfile, NULL, _IOLBF, 0);
70534865134Sbellard     }
70634865134Sbellard }
70734865134Sbellard 
70834865134Sbellard void cpu_set_log_filename(const char *filename)
70934865134Sbellard {
71034865134Sbellard     logfilename = strdup(filename);
71134865134Sbellard }
712c33a346eSbellard 
71368a79315Sbellard /* mask must never be zero */
71468a79315Sbellard void cpu_interrupt(CPUState *env, int mask)
715ea041c0eSbellard {
716ea041c0eSbellard     TranslationBlock *tb;
717ea041c0eSbellard 
71868a79315Sbellard     env->interrupt_request |= mask;
719ea041c0eSbellard     /* if the cpu is currently executing code, we must unlink it and
720ea041c0eSbellard        all the potentially executing TB */
721ea041c0eSbellard     tb = env->current_tb;
722ea041c0eSbellard     if (tb) {
723ea041c0eSbellard         tb_reset_jump_recursive(tb);
724ea041c0eSbellard     }
725ea041c0eSbellard }
726ea041c0eSbellard 
727ea041c0eSbellard 
7287501267eSbellard void cpu_abort(CPUState *env, const char *fmt, ...)
7297501267eSbellard {
7307501267eSbellard     va_list ap;
7317501267eSbellard 
7327501267eSbellard     va_start(ap, fmt);
7337501267eSbellard     fprintf(stderr, "qemu: fatal: ");
7347501267eSbellard     vfprintf(stderr, fmt, ap);
7357501267eSbellard     fprintf(stderr, "\n");
7367501267eSbellard #ifdef TARGET_I386
7377501267eSbellard     cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
7387501267eSbellard #endif
7397501267eSbellard     va_end(ap);
7407501267eSbellard     abort();
7417501267eSbellard }
7427501267eSbellard 
74366e85a21Sbellard #ifdef TARGET_I386
74466e85a21Sbellard /* unmap all maped pages and flush all associated code */
74566e85a21Sbellard void page_unmap(void)
74666e85a21Sbellard {
74761382a50Sbellard     PageDesc *pmap;
74861382a50Sbellard     int i;
74966e85a21Sbellard 
75066e85a21Sbellard     for(i = 0; i < L1_SIZE; i++) {
75166e85a21Sbellard         pmap = l1_map[i];
75266e85a21Sbellard         if (pmap) {
75361382a50Sbellard #if !defined(CONFIG_SOFTMMU)
75461382a50Sbellard             PageDesc *p;
75561382a50Sbellard             unsigned long addr;
75661382a50Sbellard             int j, ret, j1;
75761382a50Sbellard 
75866e85a21Sbellard             p = pmap;
7597c2d6a78Sbellard             for(j = 0;j < L2_SIZE;) {
76066e85a21Sbellard                 if (p->flags & PAGE_VALID) {
76166e85a21Sbellard                     addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
7627c2d6a78Sbellard                     /* we try to find a range to make less syscalls */
7637c2d6a78Sbellard                     j1 = j;
7647c2d6a78Sbellard                     p++;
7657c2d6a78Sbellard                     j++;
7667c2d6a78Sbellard                     while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
7677c2d6a78Sbellard                         p++;
7687c2d6a78Sbellard                         j++;
7697c2d6a78Sbellard                     }
7707c2d6a78Sbellard                     ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
77166e85a21Sbellard                     if (ret != 0) {
77266e85a21Sbellard                         fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
77366e85a21Sbellard                         exit(1);
77466e85a21Sbellard                     }
7757c2d6a78Sbellard                 } else {
77666e85a21Sbellard                     p++;
7777c2d6a78Sbellard                     j++;
7787c2d6a78Sbellard                 }
77966e85a21Sbellard             }
78061382a50Sbellard #endif
78166e85a21Sbellard             free(pmap);
78266e85a21Sbellard             l1_map[i] = NULL;
78366e85a21Sbellard         }
78466e85a21Sbellard     }
78566e85a21Sbellard     tb_flush();
78666e85a21Sbellard }
78766e85a21Sbellard #endif
78833417e70Sbellard 
78933417e70Sbellard void tlb_flush(CPUState *env)
79033417e70Sbellard {
79161382a50Sbellard #if !defined(CONFIG_USER_ONLY)
79233417e70Sbellard     int i;
79333417e70Sbellard     for(i = 0; i < CPU_TLB_SIZE; i++) {
79433417e70Sbellard         env->tlb_read[0][i].address = -1;
79533417e70Sbellard         env->tlb_write[0][i].address = -1;
79633417e70Sbellard         env->tlb_read[1][i].address = -1;
79733417e70Sbellard         env->tlb_write[1][i].address = -1;
79833417e70Sbellard     }
79933417e70Sbellard #endif
80033417e70Sbellard }
80133417e70Sbellard 
80261382a50Sbellard static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
80361382a50Sbellard {
80461382a50Sbellard     if (addr == (tlb_entry->address &
80561382a50Sbellard                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
80661382a50Sbellard         tlb_entry->address = -1;
80761382a50Sbellard }
80861382a50Sbellard 
80933417e70Sbellard void tlb_flush_page(CPUState *env, uint32_t addr)
81033417e70Sbellard {
81161382a50Sbellard #if !defined(CONFIG_USER_ONLY)
81233417e70Sbellard     int i;
81333417e70Sbellard 
81461382a50Sbellard     addr &= TARGET_PAGE_MASK;
81533417e70Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
81661382a50Sbellard     tlb_flush_entry(&env->tlb_read[0][i], addr);
81761382a50Sbellard     tlb_flush_entry(&env->tlb_write[0][i], addr);
81861382a50Sbellard     tlb_flush_entry(&env->tlb_read[1][i], addr);
81961382a50Sbellard     tlb_flush_entry(&env->tlb_write[1][i], addr);
82061382a50Sbellard #endif
82161382a50Sbellard }
82261382a50Sbellard 
82361382a50Sbellard /* make all write to page 'addr' trigger a TLB exception to detect
82461382a50Sbellard    self modifying code */
82561382a50Sbellard void tlb_flush_page_write(CPUState *env, uint32_t addr)
82661382a50Sbellard {
82761382a50Sbellard #if !defined(CONFIG_USER_ONLY)
82861382a50Sbellard     int i;
82961382a50Sbellard 
83061382a50Sbellard     addr &= TARGET_PAGE_MASK;
83161382a50Sbellard     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
83261382a50Sbellard     tlb_flush_entry(&env->tlb_write[0][i], addr);
83361382a50Sbellard     tlb_flush_entry(&env->tlb_write[1][i], addr);
83433417e70Sbellard #endif
83533417e70Sbellard }
83633417e70Sbellard 
83733417e70Sbellard static inline unsigned long *physpage_find_alloc(unsigned int page)
83833417e70Sbellard {
83933417e70Sbellard     unsigned long **lp, *p;
84033417e70Sbellard     unsigned int index, i;
84133417e70Sbellard 
84233417e70Sbellard     index = page >> TARGET_PAGE_BITS;
84333417e70Sbellard     lp = &l1_physmap[index >> L2_BITS];
84433417e70Sbellard     p = *lp;
84533417e70Sbellard     if (!p) {
84633417e70Sbellard         /* allocate if not found */
84733417e70Sbellard         p = malloc(sizeof(unsigned long) * L2_SIZE);
84833417e70Sbellard         for(i = 0; i < L2_SIZE; i++)
84933417e70Sbellard             p[i] = IO_MEM_UNASSIGNED;
85033417e70Sbellard         *lp = p;
85133417e70Sbellard     }
85233417e70Sbellard     return p + (index & (L2_SIZE - 1));
85333417e70Sbellard }
85433417e70Sbellard 
85533417e70Sbellard /* return NULL if no page defined (unused memory) */
85633417e70Sbellard unsigned long physpage_find(unsigned long page)
85733417e70Sbellard {
85833417e70Sbellard     unsigned long *p;
85933417e70Sbellard     unsigned int index;
86033417e70Sbellard     index = page >> TARGET_PAGE_BITS;
86133417e70Sbellard     p = l1_physmap[index >> L2_BITS];
86233417e70Sbellard     if (!p)
86333417e70Sbellard         return IO_MEM_UNASSIGNED;
86433417e70Sbellard     return p[index & (L2_SIZE - 1)];
86533417e70Sbellard }
86633417e70Sbellard 
86733417e70Sbellard /* register physical memory. 'size' must be a multiple of the target
86833417e70Sbellard    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
86933417e70Sbellard    io memory page */
87033417e70Sbellard void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
87133417e70Sbellard                                   long phys_offset)
87233417e70Sbellard {
87333417e70Sbellard     unsigned long addr, end_addr;
87433417e70Sbellard     unsigned long *p;
87533417e70Sbellard 
87633417e70Sbellard     end_addr = start_addr + size;
87733417e70Sbellard     for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
87833417e70Sbellard         p = physpage_find_alloc(addr);
87933417e70Sbellard         *p = phys_offset;
88033417e70Sbellard         if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
88133417e70Sbellard             phys_offset += TARGET_PAGE_SIZE;
88233417e70Sbellard     }
88333417e70Sbellard }
88433417e70Sbellard 
88533417e70Sbellard static uint32_t unassigned_mem_readb(uint32_t addr)
88633417e70Sbellard {
88733417e70Sbellard     return 0;
88833417e70Sbellard }
88933417e70Sbellard 
89033417e70Sbellard static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
89133417e70Sbellard {
89233417e70Sbellard }
89333417e70Sbellard 
89433417e70Sbellard static CPUReadMemoryFunc *unassigned_mem_read[3] = {
89533417e70Sbellard     unassigned_mem_readb,
89633417e70Sbellard     unassigned_mem_readb,
89733417e70Sbellard     unassigned_mem_readb,
89833417e70Sbellard };
89933417e70Sbellard 
90033417e70Sbellard static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
90133417e70Sbellard     unassigned_mem_writeb,
90233417e70Sbellard     unassigned_mem_writeb,
90333417e70Sbellard     unassigned_mem_writeb,
90433417e70Sbellard };
90533417e70Sbellard 
90633417e70Sbellard 
90733417e70Sbellard static void io_mem_init(void)
90833417e70Sbellard {
90933417e70Sbellard     io_mem_nb = 1;
91033417e70Sbellard     cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
91133417e70Sbellard }
91233417e70Sbellard 
91333417e70Sbellard /* mem_read and mem_write are arrays of functions containing the
91433417e70Sbellard    function to access byte (index 0), word (index 1) and dword (index
91533417e70Sbellard    2). All functions must be supplied. If io_index is non zero, the
91633417e70Sbellard    corresponding io zone is modified. If it is zero, a new io zone is
91733417e70Sbellard    allocated. The return value can be used with
91833417e70Sbellard    cpu_register_physical_memory(). (-1) is returned if error. */
91933417e70Sbellard int cpu_register_io_memory(int io_index,
92033417e70Sbellard                            CPUReadMemoryFunc **mem_read,
92133417e70Sbellard                            CPUWriteMemoryFunc **mem_write)
92233417e70Sbellard {
92333417e70Sbellard     int i;
92433417e70Sbellard 
92533417e70Sbellard     if (io_index <= 0) {
92633417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
92733417e70Sbellard             return -1;
92833417e70Sbellard         io_index = io_mem_nb++;
92933417e70Sbellard     } else {
93033417e70Sbellard         if (io_index >= IO_MEM_NB_ENTRIES)
93133417e70Sbellard             return -1;
93233417e70Sbellard     }
93333417e70Sbellard 
93433417e70Sbellard     for(i = 0;i < 3; i++) {
93533417e70Sbellard         io_mem_read[io_index][i] = mem_read[i];
93633417e70Sbellard         io_mem_write[io_index][i] = mem_write[i];
93733417e70Sbellard     }
93833417e70Sbellard     return io_index << IO_MEM_SHIFT;
93933417e70Sbellard }
94061382a50Sbellard 
94161382a50Sbellard #if !defined(CONFIG_USER_ONLY)
94261382a50Sbellard 
94361382a50Sbellard #define MMUSUFFIX _cmmu
94461382a50Sbellard #define GETPC() NULL
94561382a50Sbellard #define env cpu_single_env
94661382a50Sbellard 
94761382a50Sbellard #define SHIFT 0
94861382a50Sbellard #include "softmmu_template.h"
94961382a50Sbellard 
95061382a50Sbellard #define SHIFT 1
95161382a50Sbellard #include "softmmu_template.h"
95261382a50Sbellard 
95361382a50Sbellard #define SHIFT 2
95461382a50Sbellard #include "softmmu_template.h"
95561382a50Sbellard 
95661382a50Sbellard #define SHIFT 3
95761382a50Sbellard #include "softmmu_template.h"
95861382a50Sbellard 
95961382a50Sbellard #undef env
96061382a50Sbellard 
96161382a50Sbellard #endif
962