~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to softmmu_template.h

  • Committer: Bazaar Package Importer
  • Author(s): Aurelien Jarno, Aurelien Jarno
  • Date: 2008-08-25 04:38:35 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825043835-8e3tftavy8bujdch
Tags: 0.9.1-6
[ Aurelien Jarno ]
* debian/control: 
  - Update list of supported targets (Closes: bug#488339).
* debian/qemu-make-debian-root:
  - Use mktemp instead of $$ to create temporary directories (Closes: 
    bug#496394).
* debian/links:
  - Add missing links to manpages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *  Software MMU support
3
 
 * 
 
3
 *
4
4
 *  Copyright (c) 2003 Fabrice Bellard
5
5
 *
6
6
 * This library is free software; you can redistribute it and/or
39
39
#error unsupported data size
40
40
#endif
41
41
 
42
 
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, 
43
 
                                                        int is_user,
 
42
#ifdef SOFTMMU_CODE_ACCESS
 
43
#define READ_ACCESS_TYPE 2
 
44
#define ADDR_READ addr_code
 
45
#else
 
46
#define READ_ACCESS_TYPE 0
 
47
#define ADDR_READ addr_read
 
48
#endif
 
49
 
 
50
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
51
                                                        int mmu_idx,
44
52
                                                        void *retaddr);
45
 
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, 
46
 
                                                   DATA_TYPE val, 
47
 
                                                   int is_user,
48
 
                                                   void *retaddr);
49
 
 
50
 
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, 
51
 
                                              unsigned long tlb_addr)
 
53
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
 
54
                                              target_ulong tlb_addr)
52
55
{
53
56
    DATA_TYPE res;
54
57
    int index;
55
58
 
56
59
    index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
57
60
#if SHIFT <= 2
58
 
    res = io_mem_read[index][SHIFT](physaddr);
 
61
    res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
59
62
#else
60
63
#ifdef TARGET_WORDS_BIGENDIAN
61
 
    res = (uint64_t)io_mem_read[index][2](physaddr) << 32;
62
 
    res |= io_mem_read[index][2](physaddr + 4);
 
64
    res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
 
65
    res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
63
66
#else
64
 
    res = io_mem_read[index][2](physaddr);
65
 
    res |= (uint64_t)io_mem_read[index][2](physaddr + 4) << 32;
 
67
    res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
 
68
    res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
66
69
#endif
67
70
#endif /* SHIFT > 2 */
 
71
#ifdef USE_KQEMU
 
72
    env->last_io_time = cpu_get_time_fast();
 
73
#endif
68
74
    return res;
69
75
}
70
76
 
71
 
static inline void glue(io_write, SUFFIX)(unsigned long physaddr, 
72
 
                                          DATA_TYPE val,
73
 
                                          unsigned long tlb_addr,
74
 
                                          void *retaddr)
75
 
{
76
 
    int index;
77
 
 
78
 
    index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
79
 
    env->mem_write_vaddr = tlb_addr;
80
 
    env->mem_write_pc = (unsigned long)retaddr;
81
 
#if SHIFT <= 2
82
 
    io_mem_write[index][SHIFT](physaddr, val);
83
 
#else
84
 
#ifdef TARGET_WORDS_BIGENDIAN
85
 
    io_mem_write[index][2](physaddr, val >> 32);
86
 
    io_mem_write[index][2](physaddr + 4, val);
87
 
#else
88
 
    io_mem_write[index][2](physaddr, val);
89
 
    io_mem_write[index][2](physaddr + 4, val >> 32);
90
 
#endif
91
 
#endif /* SHIFT > 2 */
92
 
}
93
 
 
94
77
/* handle all cases except unaligned access which span two pages */
95
 
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr,
96
 
                                                         int is_user)
 
78
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
79
                                                         int mmu_idx)
97
80
{
98
81
    DATA_TYPE res;
99
82
    int index;
100
 
    unsigned long physaddr, tlb_addr;
 
83
    target_ulong tlb_addr;
 
84
    target_phys_addr_t physaddr;
101
85
    void *retaddr;
102
 
    
 
86
 
103
87
    /* test if there is match for unaligned or IO access */
104
88
    /* XXX: could done more in memory macro in a non portable way */
105
89
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
106
90
 redo:
107
 
    tlb_addr = env->tlb_read[is_user][index].address;
 
91
    tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
108
92
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
109
 
        physaddr = addr + env->tlb_read[is_user][index].addend;
 
93
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
110
94
        if (tlb_addr & ~TARGET_PAGE_MASK) {
111
95
            /* IO access */
112
96
            if ((addr & (DATA_SIZE - 1)) != 0)
113
97
                goto do_unaligned_access;
114
98
            res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
115
 
        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
 
99
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
116
100
            /* slow unaligned access (it spans two pages or IO) */
117
101
        do_unaligned_access:
118
102
            retaddr = GETPC();
119
 
            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, 
120
 
                                                         is_user, retaddr);
 
103
#ifdef ALIGNED_ONLY
 
104
            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 
105
#endif
 
106
            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
 
107
                                                         mmu_idx, retaddr);
121
108
        } else {
122
 
            /* unaligned access in the same page */
123
 
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
 
109
            /* unaligned/aligned access in the same page */
 
110
#ifdef ALIGNED_ONLY
 
111
            if ((addr & (DATA_SIZE - 1)) != 0) {
 
112
                retaddr = GETPC();
 
113
                do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 
114
            }
 
115
#endif
 
116
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
124
117
        }
125
118
    } else {
126
119
        /* the page is not in the TLB : fill it */
127
120
        retaddr = GETPC();
128
 
        tlb_fill(addr, 0, is_user, retaddr);
 
121
#ifdef ALIGNED_ONLY
 
122
        if ((addr & (DATA_SIZE - 1)) != 0)
 
123
            do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
 
124
#endif
 
125
        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
129
126
        goto redo;
130
127
    }
131
128
    return res;
132
129
}
133
130
 
134
131
/* handle all unaligned cases */
135
 
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, 
136
 
                                                        int is_user,
 
132
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
133
                                                        int mmu_idx,
137
134
                                                        void *retaddr)
138
135
{
139
136
    DATA_TYPE res, res1, res2;
140
137
    int index, shift;
141
 
    unsigned long physaddr, tlb_addr, addr1, addr2;
 
138
    target_phys_addr_t physaddr;
 
139
    target_ulong tlb_addr, addr1, addr2;
142
140
 
143
141
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
144
142
 redo:
145
 
    tlb_addr = env->tlb_read[is_user][index].address;
 
143
    tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
146
144
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
147
 
        physaddr = addr + env->tlb_read[is_user][index].addend;
 
145
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
148
146
        if (tlb_addr & ~TARGET_PAGE_MASK) {
149
147
            /* IO access */
150
148
            if ((addr & (DATA_SIZE - 1)) != 0)
151
149
                goto do_unaligned_access;
152
150
            res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
153
 
        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
 
151
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
154
152
        do_unaligned_access:
155
153
            /* slow unaligned access (it spans two pages) */
156
154
            addr1 = addr & ~(DATA_SIZE - 1);
157
155
            addr2 = addr1 + DATA_SIZE;
158
 
            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, 
159
 
                                                          is_user, retaddr);
160
 
            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, 
161
 
                                                          is_user, retaddr);
 
156
            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
 
157
                                                          mmu_idx, retaddr);
 
158
            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
 
159
                                                          mmu_idx, retaddr);
162
160
            shift = (addr & (DATA_SIZE - 1)) * 8;
163
161
#ifdef TARGET_WORDS_BIGENDIAN
164
162
            res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift));
168
166
            res = (DATA_TYPE)res;
169
167
        } else {
170
168
            /* unaligned/aligned access in the same page */
171
 
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
 
169
            res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
172
170
        }
173
171
    } else {
174
172
        /* the page is not in the TLB : fill it */
175
 
        tlb_fill(addr, 0, is_user, retaddr);
 
173
        tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
176
174
        goto redo;
177
175
    }
178
176
    return res;
179
177
}
180
178
 
181
 
 
182
 
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, 
 
179
#ifndef SOFTMMU_CODE_ACCESS
 
180
 
 
181
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
182
                                                   DATA_TYPE val,
 
183
                                                   int mmu_idx,
 
184
                                                   void *retaddr);
 
185
 
 
186
static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
 
187
                                          DATA_TYPE val,
 
188
                                          target_ulong tlb_addr,
 
189
                                          void *retaddr)
 
190
{
 
191
    int index;
 
192
 
 
193
    index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
 
194
    env->mem_write_vaddr = tlb_addr;
 
195
    env->mem_write_pc = (unsigned long)retaddr;
 
196
#if SHIFT <= 2
 
197
    io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
 
198
#else
 
199
#ifdef TARGET_WORDS_BIGENDIAN
 
200
    io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
 
201
    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
 
202
#else
 
203
    io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
 
204
    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
 
205
#endif
 
206
#endif /* SHIFT > 2 */
 
207
#ifdef USE_KQEMU
 
208
    env->last_io_time = cpu_get_time_fast();
 
209
#endif
 
210
}
 
211
 
 
212
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
183
213
                                                    DATA_TYPE val,
184
 
                                                    int is_user)
 
214
                                                    int mmu_idx)
185
215
{
186
 
    unsigned long physaddr, tlb_addr;
 
216
    target_phys_addr_t physaddr;
 
217
    target_ulong tlb_addr;
187
218
    void *retaddr;
188
219
    int index;
189
 
    
 
220
 
190
221
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
191
222
 redo:
192
 
    tlb_addr = env->tlb_write[is_user][index].address;
 
223
    tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
193
224
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
194
 
        physaddr = addr + env->tlb_write[is_user][index].addend;
 
225
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
195
226
        if (tlb_addr & ~TARGET_PAGE_MASK) {
196
227
            /* IO access */
197
228
            if ((addr & (DATA_SIZE - 1)) != 0)
198
229
                goto do_unaligned_access;
199
230
            retaddr = GETPC();
200
231
            glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
201
 
        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
 
232
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
202
233
        do_unaligned_access:
203
234
            retaddr = GETPC();
204
 
            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, 
205
 
                                                   is_user, retaddr);
 
235
#ifdef ALIGNED_ONLY
 
236
            do_unaligned_access(addr, 1, mmu_idx, retaddr);
 
237
#endif
 
238
            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
 
239
                                                   mmu_idx, retaddr);
206
240
        } else {
207
241
            /* aligned/unaligned access in the same page */
208
 
            glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
 
242
#ifdef ALIGNED_ONLY
 
243
            if ((addr & (DATA_SIZE - 1)) != 0) {
 
244
                retaddr = GETPC();
 
245
                do_unaligned_access(addr, 1, mmu_idx, retaddr);
 
246
            }
 
247
#endif
 
248
            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
209
249
        }
210
250
    } else {
211
251
        /* the page is not in the TLB : fill it */
212
252
        retaddr = GETPC();
213
 
        tlb_fill(addr, 1, is_user, retaddr);
 
253
#ifdef ALIGNED_ONLY
 
254
        if ((addr & (DATA_SIZE - 1)) != 0)
 
255
            do_unaligned_access(addr, 1, mmu_idx, retaddr);
 
256
#endif
 
257
        tlb_fill(addr, 1, mmu_idx, retaddr);
214
258
        goto redo;
215
259
    }
216
260
}
217
261
 
218
262
/* handles all unaligned cases */
219
 
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, 
 
263
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
220
264
                                                   DATA_TYPE val,
221
 
                                                   int is_user,
 
265
                                                   int mmu_idx,
222
266
                                                   void *retaddr)
223
267
{
224
 
    unsigned long physaddr, tlb_addr;
 
268
    target_phys_addr_t physaddr;
 
269
    target_ulong tlb_addr;
225
270
    int index, i;
226
271
 
227
272
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
228
273
 redo:
229
 
    tlb_addr = env->tlb_write[is_user][index].address;
 
274
    tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
230
275
    if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
231
 
        physaddr = addr + env->tlb_write[is_user][index].addend;
 
276
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
232
277
        if (tlb_addr & ~TARGET_PAGE_MASK) {
233
278
            /* IO access */
234
279
            if ((addr & (DATA_SIZE - 1)) != 0)
235
280
                goto do_unaligned_access;
236
281
            glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
237
 
        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
 
282
        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
238
283
        do_unaligned_access:
239
284
            /* XXX: not efficient, but simple */
240
 
            for(i = 0;i < DATA_SIZE; i++) {
 
285
            /* Note: relies on the fact that tlb_fill() does not remove the
 
286
             * previous page from the TLB cache.  */
 
287
            for(i = DATA_SIZE - 1; i >= 0; i--) {
241
288
#ifdef TARGET_WORDS_BIGENDIAN
242
 
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), 
243
 
                                          is_user, retaddr);
 
289
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
 
290
                                          mmu_idx, retaddr);
244
291
#else
245
 
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), 
246
 
                                          is_user, retaddr);
 
292
                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
 
293
                                          mmu_idx, retaddr);
247
294
#endif
248
295
            }
249
296
        } else {
250
297
            /* aligned/unaligned access in the same page */
251
 
            glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val);
 
298
            glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
252
299
        }
253
300
    } else {
254
301
        /* the page is not in the TLB : fill it */
255
 
        tlb_fill(addr, 1, is_user, retaddr);
 
302
        tlb_fill(addr, 1, mmu_idx, retaddr);
256
303
        goto redo;
257
304
    }
258
305
}
259
306
 
 
307
#endif /* !defined(SOFTMMU_CODE_ACCESS) */
 
308
 
 
309
#undef READ_ACCESS_TYPE
260
310
#undef SHIFT
261
311
#undef DATA_TYPE
262
312
#undef SUFFIX
263
313
#undef USUFFIX
264
314
#undef DATA_SIZE
 
315
#undef ADDR_READ