~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to linux-user/mmap.c

  • Committer: blueswir1
  • Date: 2007-11-25 08:48:16 UTC
  • Revision ID: git-v1:b76482e76560345c00e7d6c89199ced204a926d2
 Fix buffer mux handling for unconnected serial ports


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3737 c046a42c-6fe2-441c-8c8c-71466251a162

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include <sys/mman.h>
27
27
 
28
28
#include "qemu.h"
29
 
#include "qemu-common.h"
30
29
 
31
30
//#define DEBUG_MMAP
32
31
 
33
 
#if defined(USE_NPTL)
34
 
pthread_mutex_t mmap_mutex;
35
 
static int __thread mmap_lock_count;
36
 
 
37
 
void mmap_lock(void)
38
 
{
39
 
    if (mmap_lock_count++ == 0) {
40
 
        pthread_mutex_lock(&mmap_mutex);
41
 
    }
42
 
}
43
 
 
44
 
void mmap_unlock(void)
45
 
{
46
 
    if (--mmap_lock_count == 0) {
47
 
        pthread_mutex_unlock(&mmap_mutex);
48
 
    }
49
 
}
50
 
 
51
 
/* Grab lock to make sure things are in a consistent state after fork().  */
52
 
void mmap_fork_start(void)
53
 
{
54
 
    if (mmap_lock_count)
55
 
        abort();
56
 
    pthread_mutex_lock(&mmap_mutex);
57
 
}
58
 
 
59
 
void mmap_fork_end(int child)
60
 
{
61
 
    if (child)
62
 
        pthread_mutex_init(&mmap_mutex, NULL);
63
 
    else
64
 
        pthread_mutex_unlock(&mmap_mutex);
65
 
}
66
 
#else
67
 
/* We aren't threadsafe to start with, so no need to worry about locking.  */
68
 
void mmap_lock(void)
69
 
{
70
 
}
71
 
 
72
 
void mmap_unlock(void)
73
 
{
74
 
}
75
 
#endif
76
 
 
77
 
void *qemu_vmalloc(size_t size)
78
 
{
79
 
    void *p;
80
 
    unsigned long addr;
81
 
    mmap_lock();
82
 
    /* Use map and mark the pages as used.  */
83
 
    p = mmap(NULL, size, PROT_READ | PROT_WRITE,
84
 
             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
85
 
 
86
 
    addr = (unsigned long)p;
87
 
    if (addr == (target_ulong) addr) {
88
 
        /* Allocated region overlaps guest address space.
89
 
           This may recurse.  */
90
 
        page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
91
 
                       PAGE_RESERVED);
92
 
    }
93
 
 
94
 
    mmap_unlock();
95
 
    return p;
96
 
}
97
 
 
98
 
void *qemu_malloc(size_t size)
99
 
{
100
 
    char * p;
101
 
    size += 16;
102
 
    p = qemu_vmalloc(size);
103
 
    *(size_t *)p = size;
104
 
    return p + 16;
105
 
}
106
 
 
107
 
/* We use map, which is always zero initialized.  */
108
 
void * qemu_mallocz(size_t size)
109
 
{
110
 
    return qemu_malloc(size);
111
 
}
112
 
 
113
 
void qemu_free(void *ptr)
114
 
{
115
 
    /* FIXME: We should unmark the reserved pages here.  However this gets
116
 
       complicated when one target page spans multiple host pages, so we
117
 
       don't bother.  */
118
 
    size_t *p;
119
 
    p = (size_t *)((char *)ptr - 16);
120
 
    munmap(p, *p);
121
 
}
122
 
 
123
32
/* NOTE: all the constants are the HOST ones, but addresses are target. */
124
33
int target_mprotect(abi_ulong start, abi_ulong len, int prot)
125
34
{
140
49
    end = start + len;
141
50
    if (end < start)
142
51
        return -EINVAL;
143
 
    prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
 
52
    if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
 
53
        return -EINVAL;
144
54
    if (len == 0)
145
55
        return 0;
146
56
 
147
 
    mmap_lock();
148
57
    host_start = start & qemu_host_page_mask;
149
58
    host_end = HOST_PAGE_ALIGN(end);
150
59
    if (start > host_start) {
161
70
        }
162
71
        ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
163
72
        if (ret != 0)
164
 
            goto error;
 
73
            return ret;
165
74
        host_start += qemu_host_page_size;
166
75
    }
167
76
    if (end < host_end) {
172
81
        ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
173
82
                       prot1 & PAGE_BITS);
174
83
        if (ret != 0)
175
 
            goto error;
 
84
            return ret;
176
85
        host_end -= qemu_host_page_size;
177
86
    }
178
87
 
180
89
    if (host_start < host_end) {
181
90
        ret = mprotect(g2h(host_start), host_end - host_start, prot);
182
91
        if (ret != 0)
183
 
            goto error;
 
92
            return ret;
184
93
    }
185
94
    page_set_flags(start, start + len, prot | PAGE_VALID);
186
 
    mmap_unlock();
187
95
    return 0;
188
 
error:
189
 
    mmap_unlock();
190
 
    return ret;
191
96
}
192
97
 
193
98
/* map an incomplete host page */
253
158
static abi_ulong mmap_next_start = 0x40000000;
254
159
#endif
255
160
 
256
 
unsigned long last_brk;
257
 
 
258
161
/* find a free memory area of size 'size'. The search starts at
259
162
   'start'. If 'start' == 0, then a default start address is used.
260
163
   Return -1 if error.
261
164
*/
262
 
/* page_init() marks pages used by the host as reserved to be sure not
 
165
/* XXX: should mark pages used by the host as reserved to be sure not
263
166
   to use them. */
264
167
static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
265
168
{
266
169
    abi_ulong addr, addr1, addr_start;
267
170
    int prot;
268
 
    unsigned long new_brk;
269
 
 
270
 
    new_brk = (unsigned long)sbrk(0);
271
 
    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
272
 
        /* This is a hack to catch the host allocating memory with brk().
273
 
           If it uses mmap then we loose.
274
 
           FIXME: We really want to avoid the host allocating memory in
275
 
           the first place, and maybe leave some slack to avoid switching
276
 
           to mmap.  */
277
 
        page_set_flags(last_brk & TARGET_PAGE_MASK,
278
 
                       TARGET_PAGE_ALIGN(new_brk),
279
 
                       PAGE_RESERVED); 
280
 
    }
281
 
    last_brk = new_brk;
282
171
 
283
172
    size = HOST_PAGE_ALIGN(size);
284
173
    start = start & qemu_host_page_mask;
310
199
    abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
311
200
    unsigned long host_start;
312
201
 
313
 
    mmap_lock();
314
202
#ifdef DEBUG_MMAP
315
203
    {
316
204
        printf("mmap: start=0x" TARGET_FMT_lx
340
228
 
341
229
    if (offset & ~TARGET_PAGE_MASK) {
342
230
        errno = EINVAL;
343
 
        goto fail;
 
231
        return -1;
344
232
    }
345
233
 
346
234
    len = TARGET_PAGE_ALIGN(len);
347
235
    if (len == 0)
348
 
        goto the_end;
 
236
        return start;
349
237
    real_start = start & qemu_host_page_mask;
350
238
 
351
239
    if (!(flags & MAP_FIXED)) {
357
245
        mmap_start = mmap_find_vma(real_start, host_len);
358
246
        if (mmap_start == (abi_ulong)-1) {
359
247
            errno = ENOMEM;
360
 
            goto fail;
 
248
            return -1;
361
249
        }
362
250
        /* Note: we prefer to control the mapping address. It is
363
251
           especially important if qemu_host_page_size >
365
253
        p = mmap(g2h(mmap_start),
366
254
                 host_len, prot, flags | MAP_FIXED, fd, host_offset);
367
255
        if (p == MAP_FAILED)
368
 
            goto fail;
 
256
            return -1;
369
257
        /* update start so that it points to the file position at 'offset' */
370
258
        host_start = (unsigned long)p;
371
259
        if (!(flags & MAP_ANONYMOUS))
372
260
            host_start += offset - host_offset;
373
261
        start = h2g(host_start);
374
262
    } else {
375
 
        int flg;
376
 
        target_ulong addr;
377
 
 
378
263
        if (start & ~TARGET_PAGE_MASK) {
379
264
            errno = EINVAL;
380
 
            goto fail;
 
265
            return -1;
381
266
        }
382
267
        end = start + len;
383
268
        real_end = HOST_PAGE_ALIGN(end);
384
 
 
385
 
        for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
386
 
            flg = page_get_flags(addr);
387
 
            if (flg & PAGE_RESERVED) {
388
 
                errno = ENXIO;
389
 
                goto fail;
390
 
            }
391
 
        }
392
 
 
 
269
        
393
270
        /* worst case: we cannot map the file because the offset is not
394
271
           aligned, so we read it */
395
272
        if (!(flags & MAP_ANONYMOUS) &&
399
276
            if ((flags & MAP_TYPE) == MAP_SHARED &&
400
277
                (prot & PROT_WRITE)) {
401
278
                errno = EINVAL;
402
 
                goto fail;
 
279
                return -1;
403
280
            }
404
281
            retaddr = target_mmap(start, len, prot | PROT_WRITE,
405
282
                                  MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
406
283
                                  -1, 0);
407
284
            if (retaddr == -1)
408
 
                goto fail;
 
285
                return -1;
409
286
            pread(fd, g2h(start), len, offset);
410
287
            if (!(prot & PROT_WRITE)) {
411
288
                ret = target_mprotect(start, len, prot);
412
 
                if (ret != 0) {
413
 
                    start = ret;
414
 
                    goto the_end;
415
 
                }
 
289
                if (ret != 0)
 
290
                    return ret;
416
291
            }
417
292
            goto the_end;
418
293
        }
424
299
                ret = mmap_frag(real_start, start, end,
425
300
                                prot, flags, fd, offset);
426
301
                if (ret == -1)
427
 
                    goto fail;
 
302
                    return ret;
428
303
                goto the_end1;
429
304
            }
430
305
            ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
431
306
                            prot, flags, fd, offset);
432
307
            if (ret == -1)
433
 
                goto fail;
 
308
                return ret;
434
309
            real_start += qemu_host_page_size;
435
310
        }
436
311
        /* handle the end of the mapping */
440
315
                            prot, flags, fd,
441
316
                            offset + real_end - qemu_host_page_size - start);
442
317
            if (ret == -1)
443
 
                goto fail;
 
318
                return -1;
444
319
            real_end -= qemu_host_page_size;
445
320
        }
446
321
 
455
330
            p = mmap(g2h(real_start), real_end - real_start,
456
331
                     prot, flags, fd, offset1);
457
332
            if (p == MAP_FAILED)
458
 
                goto fail;
 
333
                return -1;
459
334
        }
460
335
    }
461
336
 the_end1:
462
337
    page_set_flags(start, start + len, prot | PAGE_VALID);
463
338
 the_end:
464
339
#ifdef DEBUG_MMAP
465
 
    printf("ret=0x" TARGET_FMT_lx "\n", start);
 
340
    printf("ret=0x%llx\n", start);
466
341
    page_dump(stdout);
467
342
    printf("\n");
468
343
#endif
469
 
    mmap_unlock();
470
344
    return start;
471
 
fail:
472
 
    mmap_unlock();
473
 
    return -1;
474
345
}
475
346
 
476
347
int target_munmap(abi_ulong start, abi_ulong len)
486
357
    len = TARGET_PAGE_ALIGN(len);
487
358
    if (len == 0)
488
359
        return -EINVAL;
489
 
    mmap_lock();
490
360
    end = start + len;
491
361
    real_start = start & qemu_host_page_mask;
492
362
    real_end = HOST_PAGE_ALIGN(end);
515
385
            real_end -= qemu_host_page_size;
516
386
    }
517
387
 
518
 
    ret = 0;
519
388
    /* unmap what we can */
520
389
    if (real_start < real_end) {
521
390
        ret = munmap(g2h(real_start), real_end - real_start);
 
391
        if (ret != 0)
 
392
            return ret;
522
393
    }
523
394
 
524
 
    if (ret == 0)
525
 
        page_set_flags(start, start + len, 0);
526
 
    mmap_unlock();
527
 
    return ret;
 
395
    page_set_flags(start, start + len, 0);
 
396
    return 0;
528
397
}
529
398
 
530
399
/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
536
405
    int prot;
537
406
    unsigned long host_addr;
538
407
 
539
 
    mmap_lock();
540
408
    /* XXX: use 5 args syscall */
541
409
    host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags);
542
 
    if (host_addr == -1) {
543
 
        new_addr = -1;
544
 
    } else {
545
 
        new_addr = h2g(host_addr);
546
 
        prot = page_get_flags(old_addr);
547
 
        page_set_flags(old_addr, old_addr + old_size, 0);
548
 
        page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
549
 
    }
550
 
    mmap_unlock();
 
410
    if (host_addr == -1)
 
411
        return -1;
 
412
    new_addr = h2g(host_addr);
 
413
    prot = page_get_flags(old_addr);
 
414
    page_set_flags(old_addr, old_addr + old_size, 0);
 
415
    page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
551
416
    return new_addr;
552
417
}
553
418
 
567
432
    start &= qemu_host_page_mask;
568
433
    return msync(g2h(start), end - start, flags);
569
434
}
 
435