Statistics
| Branch: | Revision:

root / osdep.c @ 0cb3fb1e

History | View | Annotate | Download (14.7 kB)

1
/*
2
 * QEMU low level functions
3
 * 
4
 * Copyright (c) 2003 Fabrice Bellard
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <stdarg.h>
27
#include <string.h>
28
#include <errno.h>
29
#include <unistd.h>
30

    
31
#include "cpu.h"
32

    
33
#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
34

    
35
#include <sys/mman.h>
36
#include <sys/ipc.h>
37

    
38
/* When not using soft mmu, libc independant functions are needed for
39
   the CPU core because it needs to use alternates stacks and
40
   libc/thread incompatibles settings */
41

    
42
#include <linux/unistd.h>
43

    
44
#define QEMU_SYSCALL0(name) \
45
{ \
46
long __res; \
47
__asm__ volatile ("int $0x80" \
48
        : "=a" (__res) \
49
        : "0" (__NR_##name)); \
50
return __res; \
51
}
52

    
53
#define QEMU_SYSCALL1(name,arg1) \
54
{ \
55
long __res; \
56
__asm__ volatile ("int $0x80" \
57
        : "=a" (__res) \
58
        : "0" (__NR_##name),"b" ((long)(arg1))); \
59
return __res; \
60
}
61

    
62
#define QEMU_SYSCALL2(name,arg1,arg2) \
63
{ \
64
long __res; \
65
__asm__ volatile ("int $0x80" \
66
        : "=a" (__res) \
67
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
68
return __res; \
69
}
70

    
71
#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
72
{ \
73
long __res; \
74
__asm__ volatile ("int $0x80" \
75
        : "=a" (__res) \
76
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
77
                  "d" ((long)(arg3))); \
78
return __res; \
79
}
80

    
81
#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
82
{ \
83
long __res; \
84
__asm__ volatile ("int $0x80" \
85
        : "=a" (__res) \
86
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
87
          "d" ((long)(arg3)),"S" ((long)(arg4))); \
88
return __res; \
89
} 
90

    
91
#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
92
{ \
93
long __res; \
94
__asm__ volatile ("int $0x80" \
95
        : "=a" (__res) \
96
        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
97
          "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
98
return __res; \
99
}
100

    
101
#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
102
{ \
103
long __res; \
104
__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
105
        : "=a" (__res) \
106
        : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
107
          "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
108
          "0" ((long)(arg6))); \
109
return __res; \
110
}
111

    
112
int qemu_write(int fd, const void *buf, size_t n)
113
{
114
    QEMU_SYSCALL3(write, fd, buf, n);
115
}
116

    
117

    
118

    
119
/****************************************************************/
120
/* shmat replacement */
121

    
122
int qemu_ipc(int call, unsigned long first, 
123
            unsigned long second, unsigned long third, 
124
            void *ptr, unsigned long fifth)
125
{
126
    QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
127
}
128

    
129
#define SHMAT 21
130

    
131
/* we must define shmat so that a specific address will be used when
132
   mapping the X11 ximage */
133
void *shmat(int shmid, const void *shmaddr, int shmflg)
134
{
135
    void *ptr;
136
    int ret;
137
    /* we give an address in the right memory area */
138
    if (!shmaddr)
139
        shmaddr = get_mmap_addr(8192 * 1024);
140
    ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
141
    if (ret < 0)
142
        return NULL;
143
    return ptr;
144
}
145

    
146
/****************************************************************/
147
/* sigaction bypassing the threads */
148

    
149
static int kernel_sigaction(int signum, const struct qemu_sigaction *act, 
150
                            struct qemu_sigaction *oldact, 
151
                            int sigsetsize)
152
{
153
    QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
154
}
155

    
156
int qemu_sigaction(int signum, const struct qemu_sigaction *act, 
157
                   struct qemu_sigaction *oldact)
158
{
159
    return kernel_sigaction(signum, act, oldact, 8);
160
}
161

    
162
/****************************************************************/
163
/* memory allocation */
164

    
165
//#define DEBUG_MALLOC
166

    
167
#define MALLOC_BASE       0xab000000
168
#define PHYS_RAM_BASE     0xac000000
169

    
170
#define MALLOC_ALIGN      16
171
#define BLOCK_HEADER_SIZE 16
172

    
173
typedef struct MemoryBlock {
174
    struct MemoryBlock *next;
175
    unsigned long size; /* size of block, including header */
176
} MemoryBlock;
177

    
178
static MemoryBlock *first_free_block;
179
static unsigned long malloc_addr = MALLOC_BASE;
180

    
181
static void *malloc_get_space(size_t size)
182
{
183
    void *ptr;
184
    size = TARGET_PAGE_ALIGN(size);
185
    ptr = mmap((void *)malloc_addr, size, 
186
               PROT_WRITE | PROT_READ, 
187
               MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
188
    if (ptr == MAP_FAILED)
189
        return NULL;
190
    malloc_addr += size;
191
    return ptr;
192
}
193

    
194
void *qemu_malloc(size_t size)
195
{
196
    MemoryBlock *mb, *mb1, **pmb;
197
    void *ptr;
198
    size_t size1, area_size;
199
    
200
    if (size == 0)
201
        return NULL;
202

    
203
    size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
204
    pmb = &first_free_block;
205
    for(;;) {
206
        mb = *pmb;
207
        if (mb == NULL)
208
            break;
209
        if (size <= mb->size)
210
            goto found;
211
        pmb = &mb->next;
212
    }
213
    /* no big enough blocks found: get new space */
214
    area_size = TARGET_PAGE_ALIGN(size);
215
    mb = malloc_get_space(area_size);
216
    if (!mb)
217
        return NULL;
218
    size1 = area_size - size;
219
    if (size1 > 0) {
220
        /* create a new free block */
221
        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
222
        mb1->next = NULL;
223
        mb1->size = size1;
224
        *pmb = mb1;
225
    }
226
    goto the_end;
227
 found:
228
    /* a free block was found: use it */
229
    size1 = mb->size - size;
230
    if (size1 > 0) {
231
        /* create a new free block */
232
        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
233
        mb1->next = mb->next;
234
        mb1->size = size1;
235
        *pmb = mb1;
236
    } else {
237
        /* suppress the first block */
238
        *pmb = mb->next;
239
    }
240
 the_end:
241
    mb->size = size;
242
    mb->next = NULL;
243
    ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
244
#ifdef DEBUG_MALLOC
245
    qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
246
#endif
247
    return ptr;
248
}
249

    
250
void qemu_free(void *ptr)
251
{
252
    MemoryBlock *mb;
253

    
254
    if (!ptr)
255
        return;
256
    mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
257
    mb->next = first_free_block;
258
    first_free_block = mb;
259
}
260

    
261
/****************************************************************/
262
/* virtual memory allocation */
263

    
264
unsigned long mmap_addr = PHYS_RAM_BASE;
265

    
266
void *get_mmap_addr(unsigned long size)
267
{
268
    unsigned long addr;
269
    addr = mmap_addr;
270
    mmap_addr += ((size + 4095) & ~4095) + 4096;
271
    return (void *)addr;
272
}
273

    
274
#else
275

    
276
#ifdef _WIN32
277
#include <windows.h>
278
#elif defined(_BSD)
279
#include <stdlib.h>
280
#else
281
#include <malloc.h>
282
#endif
283

    
284
int qemu_write(int fd, const void *buf, size_t n)
285
{
286
    int ret;
287
    ret = write(fd, buf, n);
288
    if (ret < 0)
289
        return -errno;
290
    else
291
        return ret;
292
}
293

    
294
void *get_mmap_addr(unsigned long size)
295
{
296
    return NULL;
297
}
298

    
299
void qemu_free(void *ptr)
300
{
301
    free(ptr);
302
}
303

    
304
void *qemu_malloc(size_t size)
305
{
306
    return malloc(size);
307
}
308

    
309
#if defined(_WIN32)
310

    
311
void *qemu_vmalloc(size_t size)
312
{
313
    /* FIXME: this is not exactly optimal solution since VirtualAlloc
314
       has 64Kb granularity, but at least it guarantees us that the
315
       memory is page aligned. */
316
    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
317
}
318

    
319
void qemu_vfree(void *ptr)
320
{
321
    VirtualFree(ptr, 0, MEM_RELEASE);
322
}
323

    
324
#elif defined(USE_KQEMU)
325

    
326
#include <sys/vfs.h>
327
#include <sys/mman.h>
328
#include <fcntl.h>
329

    
330
void *qemu_vmalloc(size_t size)
331
{
332
    static int phys_ram_fd = -1;
333
    static int phys_ram_size = 0;
334
    const char *tmpdir;
335
    char phys_ram_file[1024];
336
    void *ptr;
337
    struct statfs stfs;
338

    
339
    if (phys_ram_fd < 0) {
340
        tmpdir = getenv("QEMU_TMPDIR");
341
        if (!tmpdir)
342
            tmpdir = "/dev/shm";
343
        if (statfs(tmpdir, &stfs) == 0) {
344
            int64_t free_space;
345
            int ram_mb;
346

    
347
            extern int ram_size;
348
            free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
349
            if ((ram_size + 8192 * 1024) >= free_space) {
350
                ram_mb = (ram_size / (1024 * 1024));
351
                fprintf(stderr, 
352
                        "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
353
                        tmpdir, ram_mb);
354
                if (strcmp(tmpdir, "/dev/shm") == 0) {
355
                    fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
356
                            "umount /dev/shm\n"
357
                            "mount -t tmpfs -o size=%dm none /dev/shm\n",
358
                            ram_mb + 16);
359
                } else {
360
                    fprintf(stderr, 
361
                            "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
362
                            "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
363
                            "temporary RAM file will be opened.\n");
364
                }
365
                exit(1);
366
            }
367
        }
368
        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
369
                 tmpdir);
370
        if (mkstemp(phys_ram_file) < 0) {
371
            fprintf(stderr, 
372
                    "warning: could not create temporary file in '%s'.\n"
373
                    "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
374
                    "Using '/tmp' as fallback.\n",
375
                    tmpdir);
376
            snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
377
                     "/tmp");
378
            if (mkstemp(phys_ram_file) < 0) {
379
                fprintf(stderr, "Could not create temporary memory file '%s'\n", 
380
                        phys_ram_file);
381
                exit(1);
382
            }
383
        }
384
        phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
385
        if (phys_ram_fd < 0) {
386
            fprintf(stderr, "Could not open temporary memory file '%s'\n", 
387
                    phys_ram_file);
388
            exit(1);
389
        }
390
        unlink(phys_ram_file);
391
    }
392
    size = (size + 4095) & ~4095;
393
    ftruncate(phys_ram_fd, phys_ram_size + size);
394
    ptr = mmap(NULL, 
395
               size, 
396
               PROT_WRITE | PROT_READ, MAP_SHARED, 
397
               phys_ram_fd, phys_ram_size);
398
    if (ptr == MAP_FAILED) {
399
        fprintf(stderr, "Could not map physical memory\n");
400
        exit(1);
401
    }
402
    phys_ram_size += size;
403
    return ptr;
404
}
405

    
406
void qemu_vfree(void *ptr)
407
{
408
    /* may be useful some day, but currently we do not need to free */
409
}
410

    
411
#else
412

    
413
/* alloc shared memory pages */
414
void *qemu_vmalloc(size_t size)
415
{
416
#ifdef _BSD
417
    return valloc(size);
418
#else
419
    return memalign(4096, size);
420
#endif
421
}
422

    
423
void qemu_vfree(void *ptr)
424
{
425
    free(ptr);
426
}
427

    
428
#endif
429

    
430
#endif
431

    
432
void *qemu_mallocz(size_t size)
433
{
434
    void *ptr;
435
    ptr = qemu_malloc(size);
436
    if (!ptr)
437
        return NULL;
438
    memset(ptr, 0, size);
439
    return ptr;
440
}
441

    
442
char *qemu_strdup(const char *str)
443
{
444
    char *ptr;
445
    ptr = qemu_malloc(strlen(str) + 1);
446
    if (!ptr)
447
        return NULL;
448
    strcpy(ptr, str);
449
    return ptr;
450
}
451

    
452
/****************************************************************/
453
/* printf support */
454

    
455
static inline int qemu_isdigit(int c)
456
{
457
    return c >= '0' && c <= '9';
458
}
459

    
460
#define OUTCHAR(c)        (buflen > 0? (--buflen, *buf++ = (c)): 0)
461

    
462
/* from BSD ppp sources */
463
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
464
{
465
    int c, i, n;
466
    int width, prec, fillch;
467
    int base, len, neg;
468
    unsigned long val = 0;
469
    const char *f;
470
    char *str, *buf0;
471
    char num[32];
472
    static const char hexchars[] = "0123456789abcdef";
473

    
474
    buf0 = buf;
475
    --buflen;
476
    while (buflen > 0) {
477
        for (f = fmt; *f != '%' && *f != 0; ++f)
478
            ;
479
        if (f > fmt) {
480
            len = f - fmt;
481
            if (len > buflen)
482
                len = buflen;
483
            memcpy(buf, fmt, len);
484
            buf += len;
485
            buflen -= len;
486
            fmt = f;
487
        }
488
        if (*fmt == 0)
489
            break;
490
        c = *++fmt;
491
        width = prec = 0;
492
        fillch = ' ';
493
        if (c == '0') {
494
            fillch = '0';
495
            c = *++fmt;
496
        }
497
        if (c == '*') {
498
            width = va_arg(args, int);
499
            c = *++fmt;
500
        } else {
501
            while (qemu_isdigit(c)) {
502
                width = width * 10 + c - '0';
503
                c = *++fmt;
504
            }
505
        }
506
        if (c == '.') {
507
            c = *++fmt;
508
            if (c == '*') {
509
                prec = va_arg(args, int);
510
                c = *++fmt;
511
            } else {
512
                while (qemu_isdigit(c)) {
513
                    prec = prec * 10 + c - '0';
514
                    c = *++fmt;
515
                }
516
            }
517
        }
518
        /* modifiers */
519
        switch(c) {
520
        case 'l':
521
            c = *++fmt;
522
            break;
523
        default:
524
            break;
525
        }
526
        str = 0;
527
        base = 0;
528
        neg = 0;
529
        ++fmt;
530
        switch (c) {
531
        case 'd':
532
            i = va_arg(args, int);
533
            if (i < 0) {
534
                neg = 1;
535
                val = -i;
536
            } else
537
                val = i;
538
            base = 10;
539
            break;
540
        case 'o':
541
            val = va_arg(args, unsigned int);
542
            base = 8;
543
            break;
544
        case 'x':
545
        case 'X':
546
            val = va_arg(args, unsigned int);
547
            base = 16;
548
            break;
549
        case 'p':
550
            val = (unsigned long) va_arg(args, void *);
551
            base = 16;
552
            neg = 2;
553
            break;
554
        case 's':
555
            str = va_arg(args, char *);
556
            break;
557
        case 'c':
558
            num[0] = va_arg(args, int);
559
            num[1] = 0;
560
            str = num;
561
            break;
562
        default:
563
            *buf++ = '%';
564
            if (c != '%')
565
                --fmt;                /* so %z outputs %z etc. */
566
            --buflen;
567
            continue;
568
        }
569
        if (base != 0) {
570
            str = num + sizeof(num);
571
            *--str = 0;
572
            while (str > num + neg) {
573
                *--str = hexchars[val % base];
574
                val = val / base;
575
                if (--prec <= 0 && val == 0)
576
                    break;
577
            }
578
            switch (neg) {
579
            case 1:
580
                *--str = '-';
581
                break;
582
            case 2:
583
                *--str = 'x';
584
                *--str = '0';
585
                break;
586
            }
587
            len = num + sizeof(num) - 1 - str;
588
        } else {
589
            len = strlen(str);
590
            if (prec > 0 && len > prec)
591
                len = prec;
592
        }
593
        if (width > 0) {
594
            if (width > buflen)
595
                width = buflen;
596
            if ((n = width - len) > 0) {
597
                buflen -= n;
598
                for (; n > 0; --n)
599
                    *buf++ = fillch;
600
            }
601
        }
602
        if (len > buflen)
603
            len = buflen;
604
        memcpy(buf, str, len);
605
        buf += len;
606
        buflen -= len;
607
    }
608
    *buf = 0;
609
    return buf - buf0;
610
}
611

    
612
void qemu_vprintf(const char *fmt, va_list ap)
613
{
614
    char buf[1024];
615
    int len;
616
    
617
    len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
618
    qemu_write(1, buf, len);
619
}
620

    
621
void qemu_printf(const char *fmt, ...)
622
{
623
    va_list ap;
624
    va_start(ap, fmt);
625
    qemu_vprintf(fmt, ap);
626
    va_end(ap);
627
}
628