Statistics
| Branch: | Revision:

root / exec.c @ 0124311e

History | View | Annotate | Download (26.3 kB)

1
/*
2
 *  virtual page mapping and translated block handling
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
#include <sys/mman.h>
28

    
29
#include "config.h"
30
#include "cpu.h"
31
#include "exec-all.h"
32

    
33
//#define DEBUG_TB_INVALIDATE
34
//#define DEBUG_FLUSH
35

    
36
/* make various TB consistency checks */
37
//#define DEBUG_TB_CHECK 
38

    
39
/* threshold to flush the translated code buffer */
40
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
41

    
42
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
43

    
44
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
45
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
46
int nb_tbs;
47
/* any access to the tbs or the page table must use this lock */
48
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
49

    
50
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
51
uint8_t *code_gen_ptr;
52

    
53
/* XXX: pack the flags in the low bits of the pointer ? */
54
typedef struct PageDesc {
55
    unsigned long flags;
56
    TranslationBlock *first_tb;
57
} PageDesc;
58

    
59
#define L2_BITS 10
60
#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
61

    
62
#define L1_SIZE (1 << L1_BITS)
63
#define L2_SIZE (1 << L2_BITS)
64

    
65
static void io_mem_init(void);
66

    
67
unsigned long real_host_page_size;
68
unsigned long host_page_bits;
69
unsigned long host_page_size;
70
unsigned long host_page_mask;
71

    
72
static PageDesc *l1_map[L1_SIZE];
73

    
74
/* io memory support */
75
static unsigned long *l1_physmap[L1_SIZE];
76
CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
77
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
78
static int io_mem_nb;
79

    
80
/* log support */
81
char *logfilename = "/tmp/qemu.log";
82
FILE *logfile;
83
int loglevel;
84

    
85
static void page_init(void)
86
{
87
    /* NOTE: we can always suppose that host_page_size >=
88
       TARGET_PAGE_SIZE */
89
    real_host_page_size = getpagesize();
90
    if (host_page_size == 0)
91
        host_page_size = real_host_page_size;
92
    if (host_page_size < TARGET_PAGE_SIZE)
93
        host_page_size = TARGET_PAGE_SIZE;
94
    host_page_bits = 0;
95
    while ((1 << host_page_bits) < host_page_size)
96
        host_page_bits++;
97
    host_page_mask = ~(host_page_size - 1);
98
}
99

    
100
/* dump memory mappings */
101
void page_dump(FILE *f)
102
{
103
    unsigned long start, end;
104
    int i, j, prot, prot1;
105
    PageDesc *p;
106

    
107
    fprintf(f, "%-8s %-8s %-8s %s\n",
108
            "start", "end", "size", "prot");
109
    start = -1;
110
    end = -1;
111
    prot = 0;
112
    for(i = 0; i <= L1_SIZE; i++) {
113
        if (i < L1_SIZE)
114
            p = l1_map[i];
115
        else
116
            p = NULL;
117
        for(j = 0;j < L2_SIZE; j++) {
118
            if (!p)
119
                prot1 = 0;
120
            else
121
                prot1 = p[j].flags;
122
            if (prot1 != prot) {
123
                end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
124
                if (start != -1) {
125
                    fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
126
                            start, end, end - start, 
127
                            prot & PAGE_READ ? 'r' : '-',
128
                            prot & PAGE_WRITE ? 'w' : '-',
129
                            prot & PAGE_EXEC ? 'x' : '-');
130
                }
131
                if (prot1 != 0)
132
                    start = end;
133
                else
134
                    start = -1;
135
                prot = prot1;
136
            }
137
            if (!p)
138
                break;
139
        }
140
    }
141
}
142

    
143
static inline PageDesc *page_find_alloc(unsigned int index)
144
{
145
    PageDesc **lp, *p;
146

    
147
    lp = &l1_map[index >> L2_BITS];
148
    p = *lp;
149
    if (!p) {
150
        /* allocate if not found */
151
        p = malloc(sizeof(PageDesc) * L2_SIZE);
152
        memset(p, 0, sizeof(PageDesc) * L2_SIZE);
153
        *lp = p;
154
    }
155
    return p + (index & (L2_SIZE - 1));
156
}
157

    
158
static inline PageDesc *page_find(unsigned int index)
159
{
160
    PageDesc *p;
161

    
162
    p = l1_map[index >> L2_BITS];
163
    if (!p)
164
        return 0;
165
    return p + (index & (L2_SIZE - 1));
166
}
167

    
168
int page_get_flags(unsigned long address)
169
{
170
    PageDesc *p;
171

    
172
    p = page_find(address >> TARGET_PAGE_BITS);
173
    if (!p)
174
        return 0;
175
    return p->flags;
176
}
177

    
178
/* modify the flags of a page and invalidate the code if
179
   necessary. The flag PAGE_WRITE_ORG is positionned automatically
180
   depending on PAGE_WRITE */
181
void page_set_flags(unsigned long start, unsigned long end, int flags)
182
{
183
    PageDesc *p;
184
    unsigned long addr;
185

    
186
    start = start & TARGET_PAGE_MASK;
187
    end = TARGET_PAGE_ALIGN(end);
188
    if (flags & PAGE_WRITE)
189
        flags |= PAGE_WRITE_ORG;
190
    spin_lock(&tb_lock);
191
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
192
        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
193
        /* if the write protection is set, then we invalidate the code
194
           inside */
195
        if (!(p->flags & PAGE_WRITE) && 
196
            (flags & PAGE_WRITE) &&
197
            p->first_tb) {
198
            tb_invalidate_page(addr);
199
        }
200
        p->flags = flags;
201
    }
202
    spin_unlock(&tb_lock);
203
}
204

    
205
void cpu_exec_init(void)
206
{
207
    if (!code_gen_ptr) {
208
        code_gen_ptr = code_gen_buffer;
209
        page_init();
210
        io_mem_init();
211
    }
212
}
213

    
214
/* set to NULL all the 'first_tb' fields in all PageDescs */
215
static void page_flush_tb(void)
216
{
217
    int i, j;
218
    PageDesc *p;
219

    
220
    for(i = 0; i < L1_SIZE; i++) {
221
        p = l1_map[i];
222
        if (p) {
223
            for(j = 0; j < L2_SIZE; j++)
224
                p[j].first_tb = NULL;
225
        }
226
    }
227
}
228

    
229
/* flush all the translation blocks */
230
/* XXX: tb_flush is currently not thread safe */
231
void tb_flush(CPUState *env)
232
{
233
    int i;
234
#if defined(DEBUG_FLUSH)
235
    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
236
           code_gen_ptr - code_gen_buffer, 
237
           nb_tbs, 
238
           nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
239
#endif
240
    /* must reset current TB so that interrupts cannot modify the
241
       links while we are modifying them */
242
    env->current_tb = NULL;
243

    
244
    nb_tbs = 0;
245
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
246
        tb_hash[i] = NULL;
247
    page_flush_tb();
248
    code_gen_ptr = code_gen_buffer;
249
    /* XXX: flush processor icache at this point if cache flush is
250
       expensive */
251
}
252

    
253
#ifdef DEBUG_TB_CHECK
254

    
255
static void tb_invalidate_check(unsigned long address)
256
{
257
    TranslationBlock *tb;
258
    int i;
259
    address &= TARGET_PAGE_MASK;
260
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
261
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
262
            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
263
                  address >= tb->pc + tb->size)) {
264
                printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
265
                       address, tb->pc, tb->size);
266
            }
267
        }
268
    }
269
}
270

    
271
/* verify that all the pages have correct rights for code */
272
static void tb_page_check(void)
273
{
274
    TranslationBlock *tb;
275
    int i, flags1, flags2;
276
    
277
    for(i = 0;i < CODE_GEN_HASH_SIZE; i++) {
278
        for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) {
279
            flags1 = page_get_flags(tb->pc);
280
            flags2 = page_get_flags(tb->pc + tb->size - 1);
281
            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
282
                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
283
                       tb->pc, tb->size, flags1, flags2);
284
            }
285
        }
286
    }
287
}
288

    
289
void tb_jmp_check(TranslationBlock *tb)
290
{
291
    TranslationBlock *tb1;
292
    unsigned int n1;
293

    
294
    /* suppress any remaining jumps to this TB */
295
    tb1 = tb->jmp_first;
296
    for(;;) {
297
        n1 = (long)tb1 & 3;
298
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
299
        if (n1 == 2)
300
            break;
301
        tb1 = tb1->jmp_next[n1];
302
    }
303
    /* check end of list */
304
    if (tb1 != tb) {
305
        printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
306
    }
307
}
308

    
309
#endif
310

    
311
/* invalidate one TB */
312
static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
313
                             int next_offset)
314
{
315
    TranslationBlock *tb1;
316
    for(;;) {
317
        tb1 = *ptb;
318
        if (tb1 == tb) {
319
            *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
320
            break;
321
        }
322
        ptb = (TranslationBlock **)((char *)tb1 + next_offset);
323
    }
324
}
325

    
326
static inline void tb_jmp_remove(TranslationBlock *tb, int n)
327
{
328
    TranslationBlock *tb1, **ptb;
329
    unsigned int n1;
330

    
331
    ptb = &tb->jmp_next[n];
332
    tb1 = *ptb;
333
    if (tb1) {
334
        /* find tb(n) in circular list */
335
        for(;;) {
336
            tb1 = *ptb;
337
            n1 = (long)tb1 & 3;
338
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
339
            if (n1 == n && tb1 == tb)
340
                break;
341
            if (n1 == 2) {
342
                ptb = &tb1->jmp_first;
343
            } else {
344
                ptb = &tb1->jmp_next[n1];
345
            }
346
        }
347
        /* now we can suppress tb(n) from the list */
348
        *ptb = tb->jmp_next[n];
349

    
350
        tb->jmp_next[n] = NULL;
351
    }
352
}
353

    
354
/* reset the jump entry 'n' of a TB so that it is not chained to
355
   another TB */
356
static inline void tb_reset_jump(TranslationBlock *tb, int n)
357
{
358
    tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
359
}
360

    
361
static inline void tb_invalidate(TranslationBlock *tb, int parity)
362
{
363
    PageDesc *p;
364
    unsigned int page_index1, page_index2;
365
    unsigned int h, n1;
366
    TranslationBlock *tb1, *tb2;
367
    
368
    tb_invalidated_flag = 1;
369
    
370
    /* remove the TB from the hash list */
371
    h = tb_hash_func(tb->pc);
372
    tb_remove(&tb_hash[h], tb, 
373
              offsetof(TranslationBlock, hash_next));
374
    /* remove the TB from the page list */
375
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
376
    if ((page_index1 & 1) == parity) {
377
        p = page_find(page_index1);
378
        tb_remove(&p->first_tb, tb, 
379
                  offsetof(TranslationBlock, page_next[page_index1 & 1]));
380
    }
381
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
382
    if ((page_index2 & 1) == parity) {
383
        p = page_find(page_index2);
384
        tb_remove(&p->first_tb, tb, 
385
                  offsetof(TranslationBlock, page_next[page_index2 & 1]));
386
    }
387

    
388
    /* suppress this TB from the two jump lists */
389
    tb_jmp_remove(tb, 0);
390
    tb_jmp_remove(tb, 1);
391

    
392
    /* suppress any remaining jumps to this TB */
393
    tb1 = tb->jmp_first;
394
    for(;;) {
395
        n1 = (long)tb1 & 3;
396
        if (n1 == 2)
397
            break;
398
        tb1 = (TranslationBlock *)((long)tb1 & ~3);
399
        tb2 = tb1->jmp_next[n1];
400
        tb_reset_jump(tb1, n1);
401
        tb1->jmp_next[n1] = NULL;
402
        tb1 = tb2;
403
    }
404
    tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
405
}
406

    
407
/* invalidate all TBs which intersect with the target page starting at addr */
408
void tb_invalidate_page(unsigned long address)
409
{
410
    TranslationBlock *tb_next, *tb;
411
    unsigned int page_index;
412
    int parity1, parity2;
413
    PageDesc *p;
414
#ifdef DEBUG_TB_INVALIDATE
415
    printf("tb_invalidate_page: %lx\n", address);
416
#endif
417

    
418
    page_index = address >> TARGET_PAGE_BITS;
419
    p = page_find(page_index);
420
    if (!p)
421
        return;
422
    tb = p->first_tb;
423
    parity1 = page_index & 1;
424
    parity2 = parity1 ^ 1;
425
    while (tb != NULL) {
426
        tb_next = tb->page_next[parity1];
427
        tb_invalidate(tb, parity2);
428
        tb = tb_next;
429
    }
430
    p->first_tb = NULL;
431
}
432

    
433
/* add the tb in the target page and protect it if necessary */
434
static inline void tb_alloc_page(TranslationBlock *tb, unsigned int page_index)
435
{
436
    PageDesc *p;
437
    unsigned long host_start, host_end, addr, page_addr;
438
    int prot;
439

    
440
    p = page_find_alloc(page_index);
441
    tb->page_next[page_index & 1] = p->first_tb;
442
    p->first_tb = tb;
443
    if (p->flags & PAGE_WRITE) {
444
        /* force the host page as non writable (writes will have a
445
           page fault + mprotect overhead) */
446
        page_addr = (page_index << TARGET_PAGE_BITS);
447
        host_start = page_addr & host_page_mask;
448
        host_end = host_start + host_page_size;
449
        prot = 0;
450
        for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
451
            prot |= page_get_flags(addr);
452
#if !defined(CONFIG_SOFTMMU)
453
        mprotect((void *)host_start, host_page_size, 
454
                 (prot & PAGE_BITS) & ~PAGE_WRITE);
455
#endif
456
#if !defined(CONFIG_USER_ONLY)
457
        /* suppress soft TLB */
458
        /* XXX: must flush on all processor with same address space */
459
        tlb_flush_page_write(cpu_single_env, host_start);
460
#endif
461
#ifdef DEBUG_TB_INVALIDATE
462
        printf("protecting code page: 0x%08lx\n", 
463
               host_start);
464
#endif
465
        p->flags &= ~PAGE_WRITE;
466
    }
467
}
468

    
469
/* Allocate a new translation block. Flush the translation buffer if
470
   too many translation blocks or too much generated code. */
471
TranslationBlock *tb_alloc(unsigned long pc)
472
{
473
    TranslationBlock *tb;
474

    
475
    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
476
        (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
477
        return NULL;
478
    tb = &tbs[nb_tbs++];
479
    tb->pc = pc;
480
    return tb;
481
}
482

    
483
/* link the tb with the other TBs */
484
void tb_link(TranslationBlock *tb)
485
{
486
    unsigned int page_index1, page_index2;
487

    
488
    /* add in the page list */
489
    page_index1 = tb->pc >> TARGET_PAGE_BITS;
490
    tb_alloc_page(tb, page_index1);
491
    page_index2 = (tb->pc + tb->size - 1) >> TARGET_PAGE_BITS;
492
    if (page_index2 != page_index1) {
493
        tb_alloc_page(tb, page_index2);
494
    }
495
#ifdef DEBUG_TB_CHECK
496
    tb_page_check();
497
#endif
498
    tb->jmp_first = (TranslationBlock *)((long)tb | 2);
499
    tb->jmp_next[0] = NULL;
500
    tb->jmp_next[1] = NULL;
501

    
502
    /* init original jump addresses */
503
    if (tb->tb_next_offset[0] != 0xffff)
504
        tb_reset_jump(tb, 0);
505
    if (tb->tb_next_offset[1] != 0xffff)
506
        tb_reset_jump(tb, 1);
507
}
508

    
509
/* called from signal handler: invalidate the code and unprotect the
510
   page. Return TRUE if the fault was succesfully handled. */
511
int page_unprotect(unsigned long address)
512
{
513
    unsigned int page_index, prot, pindex;
514
    PageDesc *p, *p1;
515
    unsigned long host_start, host_end, addr;
516

    
517
    host_start = address & host_page_mask;
518
    page_index = host_start >> TARGET_PAGE_BITS;
519
    p1 = page_find(page_index);
520
    if (!p1)
521
        return 0;
522
    host_end = host_start + host_page_size;
523
    p = p1;
524
    prot = 0;
525
    for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
526
        prot |= p->flags;
527
        p++;
528
    }
529
    /* if the page was really writable, then we change its
530
       protection back to writable */
531
    if (prot & PAGE_WRITE_ORG) {
532
        pindex = (address - host_start) >> TARGET_PAGE_BITS;
533
        if (!(p1[pindex].flags & PAGE_WRITE)) {
534
#if !defined(CONFIG_SOFTMMU)
535
            mprotect((void *)host_start, host_page_size, 
536
                     (prot & PAGE_BITS) | PAGE_WRITE);
537
#endif
538
            p1[pindex].flags |= PAGE_WRITE;
539
            /* and since the content will be modified, we must invalidate
540
               the corresponding translated code. */
541
            tb_invalidate_page(address);
542
#ifdef DEBUG_TB_CHECK
543
            tb_invalidate_check(address);
544
#endif
545
            return 1;
546
        }
547
    }
548
    return 0;
549
}
550

    
551
/* call this function when system calls directly modify a memory area */
552
void page_unprotect_range(uint8_t *data, unsigned long data_size)
553
{
554
    unsigned long start, end, addr;
555

    
556
    start = (unsigned long)data;
557
    end = start + data_size;
558
    start &= TARGET_PAGE_MASK;
559
    end = TARGET_PAGE_ALIGN(end);
560
    for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
561
        page_unprotect(addr);
562
    }
563
}
564

    
565
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
566
   tb[1].tc_ptr. Return NULL if not found */
567
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
568
{
569
    int m_min, m_max, m;
570
    unsigned long v;
571
    TranslationBlock *tb;
572

    
573
    if (nb_tbs <= 0)
574
        return NULL;
575
    if (tc_ptr < (unsigned long)code_gen_buffer ||
576
        tc_ptr >= (unsigned long)code_gen_ptr)
577
        return NULL;
578
    /* binary search (cf Knuth) */
579
    m_min = 0;
580
    m_max = nb_tbs - 1;
581
    while (m_min <= m_max) {
582
        m = (m_min + m_max) >> 1;
583
        tb = &tbs[m];
584
        v = (unsigned long)tb->tc_ptr;
585
        if (v == tc_ptr)
586
            return tb;
587
        else if (tc_ptr < v) {
588
            m_max = m - 1;
589
        } else {
590
            m_min = m + 1;
591
        }
592
    } 
593
    return &tbs[m_max];
594
}
595

    
596
static void tb_reset_jump_recursive(TranslationBlock *tb);
597

    
598
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
599
{
600
    TranslationBlock *tb1, *tb_next, **ptb;
601
    unsigned int n1;
602

    
603
    tb1 = tb->jmp_next[n];
604
    if (tb1 != NULL) {
605
        /* find head of list */
606
        for(;;) {
607
            n1 = (long)tb1 & 3;
608
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
609
            if (n1 == 2)
610
                break;
611
            tb1 = tb1->jmp_next[n1];
612
        }
613
        /* we are now sure now that tb jumps to tb1 */
614
        tb_next = tb1;
615

    
616
        /* remove tb from the jmp_first list */
617
        ptb = &tb_next->jmp_first;
618
        for(;;) {
619
            tb1 = *ptb;
620
            n1 = (long)tb1 & 3;
621
            tb1 = (TranslationBlock *)((long)tb1 & ~3);
622
            if (n1 == n && tb1 == tb)
623
                break;
624
            ptb = &tb1->jmp_next[n1];
625
        }
626
        *ptb = tb->jmp_next[n];
627
        tb->jmp_next[n] = NULL;
628
        
629
        /* suppress the jump to next tb in generated code */
630
        tb_reset_jump(tb, n);
631

    
632
        /* suppress jumps in the tb on which we could have jumped */
633
        tb_reset_jump_recursive(tb_next);
634
    }
635
}
636

    
637
static void tb_reset_jump_recursive(TranslationBlock *tb)
638
{
639
    tb_reset_jump_recursive2(tb, 0);
640
    tb_reset_jump_recursive2(tb, 1);
641
}
642

    
643
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
644
   breakpoint is reached */
645
int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
646
{
647
#if defined(TARGET_I386)
648
    int i;
649

    
650
    for(i = 0; i < env->nb_breakpoints; i++) {
651
        if (env->breakpoints[i] == pc)
652
            return 0;
653
    }
654

    
655
    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
656
        return -1;
657
    env->breakpoints[env->nb_breakpoints++] = pc;
658
    tb_invalidate_page(pc);
659
    return 0;
660
#else
661
    return -1;
662
#endif
663
}
664

    
665
/* remove a breakpoint */
666
int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
667
{
668
#if defined(TARGET_I386)
669
    int i;
670
    for(i = 0; i < env->nb_breakpoints; i++) {
671
        if (env->breakpoints[i] == pc)
672
            goto found;
673
    }
674
    return -1;
675
 found:
676
    memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
677
            (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
678
    env->nb_breakpoints--;
679
    tb_invalidate_page(pc);
680
    return 0;
681
#else
682
    return -1;
683
#endif
684
}
685

    
686
/* enable or disable single step mode. EXCP_DEBUG is returned by the
687
   CPU loop after each instruction */
688
void cpu_single_step(CPUState *env, int enabled)
689
{
690
#if defined(TARGET_I386)
691
    if (env->singlestep_enabled != enabled) {
692
        env->singlestep_enabled = enabled;
693
        /* must flush all the translated code to avoid inconsistancies */
694
        tb_flush(env);
695
    }
696
#endif
697
}
698

    
699
/* enable or disable low levels log */
700
void cpu_set_log(int log_flags)
701
{
702
    loglevel = log_flags;
703
    if (loglevel && !logfile) {
704
        logfile = fopen(logfilename, "w");
705
        if (!logfile) {
706
            perror(logfilename);
707
            _exit(1);
708
        }
709
        setvbuf(logfile, NULL, _IOLBF, 0);
710
    }
711
}
712

    
713
void cpu_set_log_filename(const char *filename)
714
{
715
    logfilename = strdup(filename);
716
}
717

    
718
/* mask must never be zero, except for A20 change call */
719
void cpu_interrupt(CPUState *env, int mask)
720
{
721
    TranslationBlock *tb;
722
    
723
    env->interrupt_request |= mask;
724
    /* if the cpu is currently executing code, we must unlink it and
725
       all the potentially executing TB */
726
    tb = env->current_tb;
727
    if (tb) {
728
        tb_reset_jump_recursive(tb);
729
    }
730
}
731

    
732

    
733
void cpu_abort(CPUState *env, const char *fmt, ...)
734
{
735
    va_list ap;
736

    
737
    va_start(ap, fmt);
738
    fprintf(stderr, "qemu: fatal: ");
739
    vfprintf(stderr, fmt, ap);
740
    fprintf(stderr, "\n");
741
#ifdef TARGET_I386
742
    cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
743
#endif
744
    va_end(ap);
745
    abort();
746
}
747

    
748
#if !defined(CONFIG_USER_ONLY)
749

    
750
/* unmap all maped pages and flush all associated code */
751
static void page_unmap(CPUState *env)
752
{
753
    PageDesc *pmap;
754
    int i;
755

    
756
    for(i = 0; i < L1_SIZE; i++) {
757
        pmap = l1_map[i];
758
        if (pmap) {
759
#if !defined(CONFIG_SOFTMMU)
760
            PageDesc *p;
761
            unsigned long addr;
762
            int j, ret, j1;
763
            
764
            p = pmap;
765
            for(j = 0;j < L2_SIZE;) {
766
                if (p->flags & PAGE_VALID) {
767
                    addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
768
                    /* we try to find a range to make less syscalls */
769
                    j1 = j;
770
                    p++;
771
                    j++;
772
                    while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
773
                        p++;
774
                        j++;
775
                    }
776
                    ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
777
                    if (ret != 0) {
778
                        fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
779
                        exit(1);
780
                    }
781
                } else {
782
                    p++;
783
                    j++;
784
                }
785
            }
786
#endif
787
            free(pmap);
788
            l1_map[i] = NULL;
789
        }
790
    }
791
    tb_flush(env);
792
}
793

    
794
void tlb_flush(CPUState *env)
795
{
796
    int i;
797

    
798
    /* must reset current TB so that interrupts cannot modify the
799
       links while we are modifying them */
800
    env->current_tb = NULL;
801

    
802
    for(i = 0; i < CPU_TLB_SIZE; i++) {
803
        env->tlb_read[0][i].address = -1;
804
        env->tlb_write[0][i].address = -1;
805
        env->tlb_read[1][i].address = -1;
806
        env->tlb_write[1][i].address = -1;
807
    }
808
    /* XXX: avoid flushing the TBs */
809
    page_unmap(env);
810
}
811

    
812
static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
813
{
814
    if (addr == (tlb_entry->address & 
815
                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
816
        tlb_entry->address = -1;
817
}
818

    
819
void tlb_flush_page(CPUState *env, uint32_t addr)
820
{
821
    int i, flags;
822

    
823
    /* must reset current TB so that interrupts cannot modify the
824
       links while we are modifying them */
825
    env->current_tb = NULL;
826

    
827
    addr &= TARGET_PAGE_MASK;
828
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
829
    tlb_flush_entry(&env->tlb_read[0][i], addr);
830
    tlb_flush_entry(&env->tlb_write[0][i], addr);
831
    tlb_flush_entry(&env->tlb_read[1][i], addr);
832
    tlb_flush_entry(&env->tlb_write[1][i], addr);
833

    
834
    flags = page_get_flags(addr);
835
    if (flags & PAGE_VALID) {
836
#if !defined(CONFIG_SOFTMMU)
837
        munmap((void *)addr, TARGET_PAGE_SIZE);
838
#endif
839
        page_set_flags(addr, addr + TARGET_PAGE_SIZE, 0);
840
    }
841
}
842

    
843
/* make all write to page 'addr' trigger a TLB exception to detect
844
   self modifying code */
845
void tlb_flush_page_write(CPUState *env, uint32_t addr)
846
{
847
    int i;
848

    
849
    addr &= TARGET_PAGE_MASK;
850
    i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
851
    tlb_flush_entry(&env->tlb_write[0][i], addr);
852
    tlb_flush_entry(&env->tlb_write[1][i], addr);
853
}
854

    
855
#else
856

    
857
void tlb_flush(CPUState *env)
858
{
859
}
860

    
861
void tlb_flush_page(CPUState *env, uint32_t addr)
862
{
863
}
864

    
865
void tlb_flush_page_write(CPUState *env, uint32_t addr)
866
{
867
}
868

    
869
#endif /* defined(CONFIG_USER_ONLY) */
870

    
871
static inline unsigned long *physpage_find_alloc(unsigned int page)
872
{
873
    unsigned long **lp, *p;
874
    unsigned int index, i;
875

    
876
    index = page >> TARGET_PAGE_BITS;
877
    lp = &l1_physmap[index >> L2_BITS];
878
    p = *lp;
879
    if (!p) {
880
        /* allocate if not found */
881
        p = malloc(sizeof(unsigned long) * L2_SIZE);
882
        for(i = 0; i < L2_SIZE; i++)
883
            p[i] = IO_MEM_UNASSIGNED;
884
        *lp = p;
885
    }
886
    return p + (index & (L2_SIZE - 1));
887
}
888

    
889
/* return NULL if no page defined (unused memory) */
890
unsigned long physpage_find(unsigned long page)
891
{
892
    unsigned long *p;
893
    unsigned int index;
894
    index = page >> TARGET_PAGE_BITS;
895
    p = l1_physmap[index >> L2_BITS];
896
    if (!p)
897
        return IO_MEM_UNASSIGNED;
898
    return p[index & (L2_SIZE - 1)];
899
}
900

    
901
/* register physical memory. 'size' must be a multiple of the target
902
   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
903
   io memory page */
904
void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
905
                                  long phys_offset)
906
{
907
    unsigned long addr, end_addr;
908
    unsigned long *p;
909

    
910
    end_addr = start_addr + size;
911
    for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
912
        p = physpage_find_alloc(addr);
913
        *p = phys_offset;
914
        if ((phys_offset & ~TARGET_PAGE_MASK) == 0)
915
            phys_offset += TARGET_PAGE_SIZE;
916
    }
917
}
918

    
919
static uint32_t unassigned_mem_readb(uint32_t addr)
920
{
921
    return 0;
922
}
923

    
924
static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
925
{
926
}
927

    
928
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
929
    unassigned_mem_readb,
930
    unassigned_mem_readb,
931
    unassigned_mem_readb,
932
};
933

    
934
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
935
    unassigned_mem_writeb,
936
    unassigned_mem_writeb,
937
    unassigned_mem_writeb,
938
};
939

    
940

    
941
static void io_mem_init(void)
942
{
943
    io_mem_nb = 1;
944
    cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write);
945
}
946

    
947
/* mem_read and mem_write are arrays of functions containing the
948
   function to access byte (index 0), word (index 1) and dword (index
949
   2). All functions must be supplied. If io_index is non zero, the
950
   corresponding io zone is modified. If it is zero, a new io zone is
951
   allocated. The return value can be used with
952
   cpu_register_physical_memory(). (-1) is returned if error. */
953
int cpu_register_io_memory(int io_index,
954
                           CPUReadMemoryFunc **mem_read,
955
                           CPUWriteMemoryFunc **mem_write)
956
{
957
    int i;
958

    
959
    if (io_index <= 0) {
960
        if (io_index >= IO_MEM_NB_ENTRIES)
961
            return -1;
962
        io_index = io_mem_nb++;
963
    } else {
964
        if (io_index >= IO_MEM_NB_ENTRIES)
965
            return -1;
966
    }
967
    
968
    for(i = 0;i < 3; i++) {
969
        io_mem_read[io_index][i] = mem_read[i];
970
        io_mem_write[io_index][i] = mem_write[i];
971
    }
972
    return io_index << IO_MEM_SHIFT;
973
}
974

    
975
#if !defined(CONFIG_USER_ONLY) 
976

    
977
#define MMUSUFFIX _cmmu
978
#define GETPC() NULL
979
#define env cpu_single_env
980

    
981
#define SHIFT 0
982
#include "softmmu_template.h"
983

    
984
#define SHIFT 1
985
#include "softmmu_template.h"
986

    
987
#define SHIFT 2
988
#include "softmmu_template.h"
989

    
990
#define SHIFT 3
991
#include "softmmu_template.h"
992

    
993
#undef env
994

    
995
#endif