source: trunk/packages/xen-common/xen-common/tools/ioemu/osdep.c @ 34

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

Add xen and xen-common

File size: 15.0 KB
Line 
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#if defined(USE_KQEMU)
33#include "vl.h"
34#endif
35
36#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
37
38#include <sys/mman.h>
39#include <sys/ipc.h>
40
41/* When not using soft mmu, libc independant functions are needed for
42   the CPU core because it needs to use alternates stacks and
43   libc/thread incompatibles settings */
44
45#include <linux/unistd.h>
46
47#define QEMU_SYSCALL0(name) \
48{ \
49long __res; \
50__asm__ volatile ("int $0x80" \
51        : "=a" (__res) \
52        : "0" (__NR_##name)); \
53return __res; \
54}
55
56#define QEMU_SYSCALL1(name,arg1) \
57{ \
58long __res; \
59__asm__ volatile ("int $0x80" \
60        : "=a" (__res) \
61        : "0" (__NR_##name),"b" ((long)(arg1))); \
62return __res; \
63}
64
65#define QEMU_SYSCALL2(name,arg1,arg2) \
66{ \
67long __res; \
68__asm__ volatile ("int $0x80" \
69        : "=a" (__res) \
70        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
71return __res; \
72}
73
74#define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
75{ \
76long __res; \
77__asm__ volatile ("int $0x80" \
78        : "=a" (__res) \
79        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
80                  "d" ((long)(arg3))); \
81return __res; \
82}
83
84#define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
85{ \
86long __res; \
87__asm__ volatile ("int $0x80" \
88        : "=a" (__res) \
89        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
90          "d" ((long)(arg3)),"S" ((long)(arg4))); \
91return __res; \
92}
93
94#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
95{ \
96long __res; \
97__asm__ volatile ("int $0x80" \
98        : "=a" (__res) \
99        : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
100          "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
101return __res; \
102}
103
104#define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
105{ \
106long __res; \
107__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
108        : "=a" (__res) \
109        : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
110          "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
111          "0" ((long)(arg6))); \
112return __res; \
113}
114
115int qemu_write(int fd, const void *buf, size_t n)
116{
117    QEMU_SYSCALL3(write, fd, buf, n);
118}
119
120
121
122/****************************************************************/
123/* shmat replacement */
124
125int qemu_ipc(int call, unsigned long first, 
126            unsigned long second, unsigned long third, 
127            void *ptr, unsigned long fifth)
128{
129    QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
130}
131
132#define SHMAT 21
133
134/* we must define shmat so that a specific address will be used when
135   mapping the X11 ximage */
136void *shmat(int shmid, const void *shmaddr, int shmflg)
137{
138    void *ptr;
139    int ret;
140    /* we give an address in the right memory area */
141    if (!shmaddr)
142        shmaddr = get_mmap_addr(8192 * 1024);
143    ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
144    if (ret < 0)
145        return NULL;
146    return ptr;
147}
148
149/****************************************************************/
150/* sigaction bypassing the threads */
151
152static int kernel_sigaction(int signum, const struct qemu_sigaction *act, 
153                            struct qemu_sigaction *oldact, 
154                            int sigsetsize)
155{
156    QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
157}
158
159int qemu_sigaction(int signum, const struct qemu_sigaction *act, 
160                   struct qemu_sigaction *oldact)
161{
162    return kernel_sigaction(signum, act, oldact, 8);
163}
164
165/****************************************************************/
166/* memory allocation */
167
168//#define DEBUG_MALLOC
169
170#define MALLOC_BASE       0xab000000
171#define PHYS_RAM_BASE     0xac000000
172
173#define MALLOC_ALIGN      16
174#define BLOCK_HEADER_SIZE 16
175
176typedef struct MemoryBlock {
177    struct MemoryBlock *next;
178    unsigned long size; /* size of block, including header */
179} MemoryBlock;
180
181static MemoryBlock *first_free_block;
182static unsigned long malloc_addr = MALLOC_BASE;
183
184static void *malloc_get_space(size_t size)
185{
186    void *ptr;
187    size = TARGET_PAGE_ALIGN(size);
188    ptr = mmap((void *)malloc_addr, size, 
189               PROT_WRITE | PROT_READ, 
190               MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
191    if (ptr == MAP_FAILED)
192        return NULL;
193    malloc_addr += size;
194    return ptr;
195}
196
197void *qemu_malloc(size_t size)
198{
199    MemoryBlock *mb, *mb1, **pmb;
200    void *ptr;
201    size_t size1, area_size;
202   
203    if (size == 0)
204        return NULL;
205
206    size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
207    pmb = &first_free_block;
208    for(;;) {
209        mb = *pmb;
210        if (mb == NULL)
211            break;
212        if (size <= mb->size)
213            goto found;
214        pmb = &mb->next;
215    }
216    /* no big enough blocks found: get new space */
217    area_size = TARGET_PAGE_ALIGN(size);
218    mb = malloc_get_space(area_size);
219    if (!mb)
220        return NULL;
221    size1 = area_size - size;
222    if (size1 > 0) {
223        /* create a new free block */
224        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
225        mb1->next = NULL;
226        mb1->size = size1;
227        *pmb = mb1;
228    }
229    goto the_end;
230 found:
231    /* a free block was found: use it */
232    size1 = mb->size - size;
233    if (size1 > 0) {
234        /* create a new free block */
235        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
236        mb1->next = mb->next;
237        mb1->size = size1;
238        *pmb = mb1;
239    } else {
240        /* suppress the first block */
241        *pmb = mb->next;
242    }
243 the_end:
244    mb->size = size;
245    mb->next = NULL;
246    ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
247#ifdef DEBUG_MALLOC
248    qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
249#endif
250    return ptr;
251}
252
253void qemu_free(void *ptr)
254{
255    MemoryBlock *mb;
256
257    if (!ptr)
258        return;
259    mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
260    mb->next = first_free_block;
261    first_free_block = mb;
262}
263
264/****************************************************************/
265/* virtual memory allocation */
266
267unsigned long mmap_addr = PHYS_RAM_BASE;
268
269void *get_mmap_addr(unsigned long size)
270{
271    unsigned long addr;
272    addr = mmap_addr;
273    mmap_addr += ((size + 4095) & ~4095) + 4096;
274    return (void *)addr;
275}
276
277#else
278
279#ifdef _WIN32
280#include <windows.h>
281#elif defined(_BSD)
282#include <stdlib.h>
283#else
284#include <malloc.h>
285#endif
286
287int qemu_write(int fd, const void *buf, size_t n)
288{
289    int ret;
290    ret = write(fd, buf, n);
291    if (ret < 0)
292        return -errno;
293    else
294        return ret;
295}
296
297void *get_mmap_addr(unsigned long size)
298{
299    return NULL;
300}
301
302void qemu_free(void *ptr)
303{
304    free(ptr);
305}
306
307void *qemu_malloc(size_t size)
308{
309    return malloc(size);
310}
311
312#if defined(_WIN32)
313
314void *qemu_vmalloc(size_t size)
315{
316    /* FIXME: this is not exactly optimal solution since VirtualAlloc
317       has 64Kb granularity, but at least it guarantees us that the
318       memory is page aligned. */
319    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
320}
321
322void qemu_vfree(void *ptr)
323{
324    VirtualFree(ptr, 0, MEM_RELEASE);
325}
326
327#else
328
329#if defined(USE_KQEMU)
330
331#include <sys/vfs.h>
332#include <sys/mman.h>
333#include <fcntl.h>
334
335void *kqemu_vmalloc(size_t size)
336{
337    static int phys_ram_fd = -1;
338    static int phys_ram_size = 0;
339    const char *tmpdir;
340    char phys_ram_file[1024];
341    void *ptr;
342    struct statfs stfs;
343
344    if (phys_ram_fd < 0) {
345        tmpdir = getenv("QEMU_TMPDIR");
346        if (!tmpdir)
347            tmpdir = "/dev/shm";
348        if (statfs(tmpdir, &stfs) == 0) {
349            int64_t free_space;
350            int ram_mb;
351
352            extern int ram_size;
353            free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
354            if ((ram_size + 8192 * 1024) >= free_space) {
355                ram_mb = (ram_size / (1024 * 1024));
356                fprintf(stderr, 
357                        "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
358                        tmpdir, ram_mb);
359                if (strcmp(tmpdir, "/dev/shm") == 0) {
360                    fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
361                            "umount /dev/shm\n"
362                            "mount -t tmpfs -o size=%dm none /dev/shm\n",
363                            ram_mb + 16);
364                } else {
365                    fprintf(stderr, 
366                            "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
367                            "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
368                            "temporary RAM file will be opened.\n");
369                }
370                fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
371                exit(1);
372            }
373        }
374        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
375                 tmpdir);
376        if (mkstemp(phys_ram_file) < 0) {
377            fprintf(stderr, 
378                    "warning: could not create temporary file in '%s'.\n"
379                    "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
380                    "Using '/tmp' as fallback.\n",
381                    tmpdir);
382            snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
383                     "/tmp");
384            if (mkstemp(phys_ram_file) < 0) {
385                fprintf(stderr, "Could not create temporary memory file '%s'\n", 
386                        phys_ram_file);
387                exit(1);
388            }
389        }
390        phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
391        if (phys_ram_fd < 0) {
392            fprintf(stderr, "Could not open temporary memory file '%s'\n", 
393                    phys_ram_file);
394            exit(1);
395        }
396        unlink(phys_ram_file);
397    }
398    size = (size + 4095) & ~4095;
399    ftruncate(phys_ram_fd, phys_ram_size + size);
400    ptr = mmap(NULL, 
401               size, 
402               PROT_WRITE | PROT_READ, MAP_SHARED, 
403               phys_ram_fd, phys_ram_size);
404    if (ptr == MAP_FAILED) {
405        fprintf(stderr, "Could not map physical memory\n");
406        exit(1);
407    }
408    phys_ram_size += size;
409    return ptr;
410}
411
412void kqemu_vfree(void *ptr)
413{
414    /* may be useful some day, but currently we do not need to free */
415}
416
417#endif
418
419/* alloc shared memory pages */
420void *qemu_vmalloc(size_t size)
421{
422#if defined(USE_KQEMU)
423    if (kqemu_allowed)
424        return kqemu_vmalloc(size);
425#endif
426#ifdef _BSD
427    return valloc(size);
428#else
429    return memalign(4096, size);
430#endif
431}
432
433void qemu_vfree(void *ptr)
434{
435#if defined(USE_KQEMU)
436    if (kqemu_allowed)
437        kqemu_vfree(ptr);
438#endif
439    free(ptr);
440}
441
442#endif
443
444#endif
445
446void *qemu_mallocz(size_t size)
447{
448    void *ptr;
449    ptr = qemu_malloc(size);
450    if (!ptr)
451        return NULL;
452    memset(ptr, 0, size);
453    return ptr;
454}
455
456char *qemu_strdup(const char *str)
457{
458    char *ptr;
459    ptr = qemu_malloc(strlen(str) + 1);
460    if (!ptr)
461        return NULL;
462    strcpy(ptr, str);
463    return ptr;
464}
465
466/****************************************************************/
467/* printf support */
468
469static inline int qemu_isdigit(int c)
470{
471    return c >= '0' && c <= '9';
472}
473
474#define OUTCHAR(c)      (buflen > 0? (--buflen, *buf++ = (c)): 0)
475
476/* from BSD ppp sources */
477int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
478{
479    int c, i, n;
480    int width, prec, fillch;
481    int base, len, neg;
482    unsigned long val = 0;
483    const char *f;
484    char *str, *buf0;
485    char num[32];
486    static const char hexchars[] = "0123456789abcdef";
487
488    buf0 = buf;
489    --buflen;
490    while (buflen > 0) {
491        for (f = fmt; *f != '%' && *f != 0; ++f)
492            ;
493        if (f > fmt) {
494            len = f - fmt;
495            if (len > buflen)
496                len = buflen;
497            memcpy(buf, fmt, len);
498            buf += len;
499            buflen -= len;
500            fmt = f;
501        }
502        if (*fmt == 0)
503            break;
504        c = *++fmt;
505        width = prec = 0;
506        fillch = ' ';
507        if (c == '0') {
508            fillch = '0';
509            c = *++fmt;
510        }
511        if (c == '*') {
512            width = va_arg(args, int);
513            c = *++fmt;
514        } else {
515            while (qemu_isdigit(c)) {
516                width = width * 10 + c - '0';
517                c = *++fmt;
518            }
519        }
520        if (c == '.') {
521            c = *++fmt;
522            if (c == '*') {
523                prec = va_arg(args, int);
524                c = *++fmt;
525            } else {
526                while (qemu_isdigit(c)) {
527                    prec = prec * 10 + c - '0';
528                    c = *++fmt;
529                }
530            }
531        }
532        /* modifiers */
533        switch(c) {
534        case 'l':
535            c = *++fmt;
536            break;
537        default:
538            break;
539        }
540        str = 0;
541        base = 0;
542        neg = 0;
543        ++fmt;
544        switch (c) {
545        case 'd':
546            i = va_arg(args, int);
547            if (i < 0) {
548                neg = 1;
549                val = -i;
550            } else
551                val = i;
552            base = 10;
553            break;
554        case 'o':
555            val = va_arg(args, unsigned int);
556            base = 8;
557            break;
558        case 'x':
559        case 'X':
560            val = va_arg(args, unsigned int);
561            base = 16;
562            break;
563        case 'p':
564            val = (unsigned long) va_arg(args, void *);
565            base = 16;
566            neg = 2;
567            break;
568        case 's':
569            str = va_arg(args, char *);
570            break;
571        case 'c':
572            num[0] = va_arg(args, int);
573            num[1] = 0;
574            str = num;
575            break;
576        default:
577            *buf++ = '%';
578            if (c != '%')
579                --fmt;          /* so %z outputs %z etc. */
580            --buflen;
581            continue;
582        }
583        if (base != 0) {
584            str = num + sizeof(num);
585            *--str = 0;
586            while (str > num + neg) {
587                *--str = hexchars[val % base];
588                val = val / base;
589                if (--prec <= 0 && val == 0)
590                    break;
591            }
592            switch (neg) {
593            case 1:
594                *--str = '-';
595                break;
596            case 2:
597                *--str = 'x';
598                *--str = '0';
599                break;
600            }
601            len = num + sizeof(num) - 1 - str;
602        } else {
603            len = strlen(str);
604            if (prec > 0 && len > prec)
605                len = prec;
606        }
607        if (width > 0) {
608            if (width > buflen)
609                width = buflen;
610            if ((n = width - len) > 0) {
611                buflen -= n;
612                for (; n > 0; --n)
613                    *buf++ = fillch;
614            }
615        }
616        if (len > buflen)
617            len = buflen;
618        memcpy(buf, str, len);
619        buf += len;
620        buflen -= len;
621    }
622    *buf = 0;
623    return buf - buf0;
624}
625
626void qemu_vprintf(const char *fmt, va_list ap)
627{
628    char buf[1024];
629    int len;
630   
631    len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
632    qemu_write(1, buf, len);
633}
634
635void qemu_printf(const char *fmt, ...)
636{
637    va_list ap;
638    va_start(ap, fmt);
639    qemu_vprintf(fmt, ap);
640    va_end(ap);
641}
642
Note: See TracBrowser for help on using the repository browser.