source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/target-i386-dm/exec-dm.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 15.6 KB
Line 
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 "config.h"
21#ifdef _WIN32
22#include <windows.h>
23#else
24#include <sys/types.h>
25#include <sys/mman.h>
26#endif
27#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
35#include <xen/hvm/e820.h>
36
37#include "cpu.h"
38#include "exec-all.h"
39#include "vl.h"
40
41//#define DEBUG_TB_INVALIDATE
42//#define DEBUG_FLUSH
43//#define DEBUG_TLB
44
45/* make various TB consistency checks */
46//#define DEBUG_TB_CHECK
47//#define DEBUG_TLB_CHECK
48
49#ifndef CONFIG_DM
50/* threshold to flush the translated code buffer */
51#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
52
53#define SMC_BITMAP_USE_THRESHOLD 10
54
55#define MMAP_AREA_START        0x00000000
56#define MMAP_AREA_END          0xa8000000
57
58TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
59TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
60TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
61int nb_tbs;
62/* any access to the tbs or the page table must use this lock */
63spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
64
65uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
66uint8_t *code_gen_ptr;
67#endif /* !CONFIG_DM */
68
69uint64_t phys_ram_size;
70extern uint64_t ram_size;
71int phys_ram_fd;
72uint8_t *phys_ram_base;
73uint8_t *phys_ram_dirty;
74
75CPUState *first_cpu;
76/* current CPU in the current thread. It is only valid inside
77   cpu_exec() */
78CPUState *cpu_single_env; 
79
80typedef struct PageDesc {
81    /* list of TBs intersecting this ram page */
82    TranslationBlock *first_tb;
83    /* in order to optimize self modifying code, we count the number
84       of lookups we do to a given page to use a bitmap */
85    unsigned int code_write_count;
86    uint8_t *code_bitmap;
87#if defined(CONFIG_USER_ONLY)
88    unsigned long flags;
89#endif
90} PageDesc;
91
92typedef struct PhysPageDesc {
93    /* offset in host memory of the page + io_index in the low 12 bits */
94    unsigned long phys_offset;
95} PhysPageDesc;
96
97typedef struct VirtPageDesc {
98    /* physical address of code page. It is valid only if 'valid_tag'
99       matches 'virt_valid_tag' */ 
100    target_ulong phys_addr; 
101    unsigned int valid_tag;
102#if !defined(CONFIG_SOFTMMU)
103    /* original page access rights. It is valid only if 'valid_tag'
104       matches 'virt_valid_tag' */
105    unsigned int prot;
106#endif
107} VirtPageDesc;
108
109#define L2_BITS 10
110#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
111
112#define L1_SIZE (1 << L1_BITS)
113#define L2_SIZE (1 << L2_BITS)
114
115unsigned long qemu_real_host_page_size;
116unsigned long qemu_host_page_bits;
117unsigned long qemu_host_page_size;
118unsigned long qemu_host_page_mask;
119
120/* io memory support */
121CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
122CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
123void *io_mem_opaque[IO_MEM_NB_ENTRIES];
124static int io_mem_nb = 1;
125
126/* log support */
127char *logfilename = "/tmp/qemu.log";
128FILE *logfile;
129int loglevel;
130
131#ifdef MAPCACHE
132pthread_mutex_t mapcache_mutex;
133#endif
134
135void cpu_exec_init(CPUState *env)
136{
137    CPUState **penv;
138    int cpu_index;
139#ifdef MAPCACHE
140    pthread_mutexattr_t mxattr; 
141#endif
142
143    env->next_cpu = NULL;
144    penv = &first_cpu;
145    cpu_index = 0;
146    while (*penv != NULL) {
147        penv = (CPUState **)&(*penv)->next_cpu;
148        cpu_index++;
149    }
150    env->cpu_index = cpu_index;
151    *penv = env;
152
153    /* alloc dirty bits array */
154    phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
155
156#ifdef MAPCACHE
157    /* setup memory access mutex to protect mapcache */
158    pthread_mutexattr_init(&mxattr); 
159    pthread_mutexattr_settype(&mxattr, PTHREAD_MUTEX_RECURSIVE);
160    pthread_mutex_init(&mapcache_mutex, &mxattr); 
161    pthread_mutexattr_destroy(&mxattr); 
162#endif
163}
164
165/* enable or disable low levels log */
166void cpu_set_log(int log_flags)
167{
168    loglevel = log_flags;
169    if (!logfile) {
170        logfile = fopen(logfilename, "w");
171        if (!logfile) {
172            perror(logfilename);
173            _exit(1);
174        }
175#if !defined(CONFIG_SOFTMMU)
176        /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
177        {
178            static uint8_t logfile_buf[4096];
179            setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
180        }
181#else
182        setvbuf(logfile, NULL, _IOLBF, 0);
183#endif
184        stdout = logfile;
185        stderr = logfile;
186    }
187}
188
189void cpu_set_log_filename(const char *filename)
190{
191    logfilename = strdup(filename);
192}
193
194/* mask must never be zero, except for A20 change call */
195void cpu_interrupt(CPUState *env, int mask)
196{
197    env->interrupt_request |= mask;
198}
199
200void cpu_reset_interrupt(CPUState *env, int mask)
201{
202    env->interrupt_request &= ~mask;
203}
204
205CPULogItem cpu_log_items[] = {
206    { CPU_LOG_TB_OUT_ASM, "out_asm", 
207      "show generated host assembly code for each compiled TB" },
208    { CPU_LOG_TB_IN_ASM, "in_asm",
209      "show target assembly code for each compiled TB" },
210    { CPU_LOG_TB_OP, "op", 
211      "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
212#ifdef TARGET_I386
213    { CPU_LOG_TB_OP_OPT, "op_opt",
214      "show micro ops after optimization for each compiled TB" },
215#endif
216    { CPU_LOG_INT, "int",
217      "show interrupts/exceptions in short format" },
218    { CPU_LOG_EXEC, "exec",
219      "show trace before each executed TB (lots of logs)" },
220    { CPU_LOG_TB_CPU, "cpu",
221      "show CPU state before bloc translation" },
222#ifdef TARGET_I386
223    { CPU_LOG_PCALL, "pcall",
224      "show protected mode far calls/returns/exceptions" },
225#endif
226#ifdef DEBUG_IOPORT
227    { CPU_LOG_IOPORT, "ioport",
228      "show all i/o ports accesses" },
229#endif
230    { 0, NULL, NULL },
231};
232
233static int cmp1(const char *s1, int n, const char *s2)
234{
235    if (strlen(s2) != n)
236        return 0;
237    return memcmp(s1, s2, n) == 0;
238}
239     
240/* takes a comma separated list of log masks. Return 0 if error. */
241int cpu_str_to_log_mask(const char *str)
242{
243    CPULogItem *item;
244    int mask;
245    const char *p, *p1;
246
247    p = str;
248    mask = 0;
249    for(;;) {
250        p1 = strchr(p, ',');
251        if (!p1)
252            p1 = p + strlen(p);
253        if(cmp1(p,p1-p,"all")) {
254                for(item = cpu_log_items; item->mask != 0; item++) {
255                        mask |= item->mask;
256                }
257        } else {
258        for(item = cpu_log_items; item->mask != 0; item++) {
259            if (cmp1(p, p1 - p, item->name))
260                goto found;
261        }
262        return 0;
263        }
264    found:
265        mask |= item->mask;
266        if (*p1 != ',')
267            break;
268        p = p1 + 1;
269    }
270    return mask;
271}
272
273void cpu_abort(CPUState *env, const char *fmt, ...)
274{
275    va_list ap;
276
277    va_start(ap, fmt);
278    fprintf(stderr, "qemu: fatal: ");
279    vfprintf(stderr, fmt, ap);
280    fprintf(stderr, "\n");
281    va_end(ap);
282    abort();
283}
284
285
286/* XXX: Simple implementation. Fix later */
287#define MAX_MMIO 32
288struct mmio_space {
289        target_phys_addr_t start;
290        unsigned long size;
291        unsigned long io_index;
292} mmio[MAX_MMIO];
293unsigned long mmio_cnt;
294
295/* register physical memory. 'size' must be a multiple of the target
296   page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
297   io memory page */
298void cpu_register_physical_memory(target_phys_addr_t start_addr, 
299                                  unsigned long size,
300                                  unsigned long phys_offset)
301{
302    int i;
303
304    for (i = 0; i < mmio_cnt; i++) { 
305        if(mmio[i].start == start_addr) {
306            mmio[i].io_index = phys_offset;
307            mmio[i].size = size;
308            return;
309        }
310    }
311
312    if (mmio_cnt == MAX_MMIO) {
313        fprintf(logfile, "too many mmio regions\n");
314        exit(-1);
315    }
316
317    mmio[mmio_cnt].io_index = phys_offset;
318    mmio[mmio_cnt].start = start_addr;
319    mmio[mmio_cnt++].size = size;
320}
321
322/* mem_read and mem_write are arrays of functions containing the
323   function to access byte (index 0), word (index 1) and dword (index
324   2). All functions must be supplied. If io_index is non zero, the
325   corresponding io zone is modified. If it is zero, a new io zone is
326   allocated. The return value can be used with
327   cpu_register_physical_memory(). (-1) is returned if error. */
328int cpu_register_io_memory(int io_index,
329                           CPUReadMemoryFunc **mem_read,
330                           CPUWriteMemoryFunc **mem_write,
331                           void *opaque)
332{
333    int i;
334
335    if (io_index <= 0) {
336        if (io_index >= IO_MEM_NB_ENTRIES)
337            return -1;
338        io_index = io_mem_nb++;
339    } else {
340        if (io_index >= IO_MEM_NB_ENTRIES)
341            return -1;
342    }
343   
344    for(i = 0;i < 3; i++) {
345        io_mem_read[io_index][i] = mem_read[i];
346        io_mem_write[io_index][i] = mem_write[i];
347    }
348    io_mem_opaque[io_index] = opaque;
349    return io_index << IO_MEM_SHIFT;
350}
351
352CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
353{
354    return io_mem_write[io_index >> IO_MEM_SHIFT];
355}
356
357CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
358{
359    return io_mem_read[io_index >> IO_MEM_SHIFT];
360}
361
362#ifdef __ia64__
363/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
364 * So to emulate right behavior that guest OS is assumed, we need to flush
365 * I/D cache here.
366 */
367static void sync_icache(unsigned long address, int len)
368{
369    int l;
370
371    for(l = 0; l < (len + 32); l += 32)
372        __ia64_fc(address + l);
373
374    ia64_sync_i();
375    ia64_srlz_i();
376}
377#endif
378
379/* physical memory access (slow version, mainly for debug) */
380#if defined(CONFIG_USER_ONLY)
381void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
382                            int len, int is_write)
383{
384    int l, flags;
385    target_ulong page;
386
387    while (len > 0) {
388        page = addr & TARGET_PAGE_MASK;
389        l = (page + TARGET_PAGE_SIZE) - addr;
390        if (l > len)
391            l = len;
392        flags = page_get_flags(page);
393        if (!(flags & PAGE_VALID))
394            return;
395        if (is_write) {
396            if (!(flags & PAGE_WRITE))
397                return;
398            memcpy((uint8_t *)addr, buf, len);
399        } else {
400            if (!(flags & PAGE_READ))
401                return;
402            memcpy(buf, (uint8_t *)addr, len);
403        }
404        len -= l;
405        buf += l;
406        addr += l;
407    }
408}
409#else
410
411int iomem_index(target_phys_addr_t addr)
412{
413        int i;
414
415        for (i = 0; i < mmio_cnt; i++) {
416                unsigned long start, end;
417
418                start = mmio[i].start;
419                end = mmio[i].start + mmio[i].size;
420
421                if ((addr >= start) && (addr < end)){
422                        return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
423                }
424        }
425        return 0;
426}
427
428#if defined(__i386__) || defined(__x86_64__)
429#define phys_ram_addr(x) (qemu_map_cache(x))
430#elif defined(__ia64__)
431#define phys_ram_addr(x) ((addr < ram_size) ? (phys_ram_base + (x)) : NULL)
432#endif
433
434extern unsigned long *logdirty_bitmap;
435extern unsigned long logdirty_bitmap_size;
436
437void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
438                            int len, int is_write)
439{
440    int l, io_index;
441    uint8_t *ptr;
442    uint32_t val;
443
444    mapcache_lock();
445
446    while (len > 0) {
447        /* How much can we copy before the next page boundary? */
448        l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); 
449        if (l > len)
450            l = len;
451
452        io_index = iomem_index(addr);
453        if (is_write) {
454            if (io_index) {
455                if (l >= 4 && ((addr & 3) == 0)) {
456                    /* 32 bit read access */
457                    val = ldl_raw(buf);
458                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
459                    l = 4;
460                } else if (l >= 2 && ((addr & 1) == 0)) {
461                    /* 16 bit read access */
462                    val = lduw_raw(buf);
463                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
464                    l = 2;
465                } else {
466                    /* 8 bit access */
467                    val = ldub_raw(buf);
468                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
469                    l = 1;
470                }
471            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
472                /* Writing to RAM */
473                memcpy(ptr, buf, l);
474                if (logdirty_bitmap != NULL) {
475                    /* Record that we have dirtied this frame */
476                    unsigned long pfn = addr >> TARGET_PAGE_BITS;
477                    if (pfn / 8 >= logdirty_bitmap_size) {
478                        fprintf(logfile, "dirtying pfn %lx >= bitmap "
479                                "size %lx\n", pfn, logdirty_bitmap_size * 8);
480                    } else {
481                        logdirty_bitmap[pfn / HOST_LONG_BITS]
482                            |= 1UL << pfn % HOST_LONG_BITS;
483                    }
484                }
485#ifdef __ia64__
486                sync_icache(ptr, l);
487#endif
488            }
489        } else {
490            if (io_index) {
491                if (l >= 4 && ((addr & 3) == 0)) {
492                    /* 32 bit read access */
493                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
494                    stl_raw(buf, val);
495                    l = 4;
496                } else if (l >= 2 && ((addr & 1) == 0)) {
497                    /* 16 bit read access */
498                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
499                    stw_raw(buf, val);
500                    l = 2;
501                } else {
502                    /* 8 bit access */
503                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
504                    stb_raw(buf, val);
505                    l = 1;
506                }
507            } else if ((ptr = phys_ram_addr(addr)) != NULL) {
508                /* Reading from RAM */
509                memcpy(buf, ptr, l);
510            } else {
511                /* Neither RAM nor known MMIO space */
512                memset(buf, 0xff, len); 
513            }
514        }
515        len -= l;
516        buf += l;
517        addr += l;
518    }
519
520    mapcache_unlock();
521}
522#endif
523
524/* virtual memory access for debug */
525int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 
526                        uint8_t *buf, int len, int is_write)
527{
528    int l;
529    target_ulong page, phys_addr;
530
531    while (len > 0) {
532        page = addr & TARGET_PAGE_MASK;
533        phys_addr = cpu_get_phys_page_debug(env, page);
534        /* if no physical page mapped, return an error */
535        if (phys_addr == -1)
536            return -1;
537        l = (page + TARGET_PAGE_SIZE) - addr;
538        if (l > len)
539            l = len;
540        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), 
541                               buf, l, is_write);
542        len -= l;
543        buf += l;
544        addr += l;
545    }
546    return 0;
547}
548
549void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
550                                     int dirty_flags)
551{
552        unsigned long length;
553        int i, mask, len;
554        uint8_t *p;
555
556        start &= TARGET_PAGE_MASK;
557        end = TARGET_PAGE_ALIGN(end);
558
559        length = end - start;
560        if (length == 0)
561                return;
562        mask = ~dirty_flags;
563        p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
564        len = length >> TARGET_PAGE_BITS;
565        for(i = 0; i < len; i++)
566                p[i] &= mask;
567
568        return;
569}
Note: See TracBrowser for help on using the repository browser.