Statistics
| Branch: | Revision:

root / osdep.c @ 16f62432

History | View | Annotate | Download (10.1 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 <sys/mman.h>
29
#include <sys/ipc.h>
30
#include <errno.h>
31
#include <unistd.h>
32

    
33
#include "cpu.h"
34

    
35
#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
36

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

    
41
#include <linux/unistd.h>
42

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

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

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

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

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

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

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

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

    
116

    
117

    
118
/****************************************************************/
119
/* shmat replacement */
120

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

    
128
#define SHMAT 21
129

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

    
145
/****************************************************************/
146
/* memory allocation */
147

    
148
//#define DEBUG_MALLOC
149

    
150
#define MALLOC_BASE       0xab000000
151
#define PHYS_RAM_BASE     0xac000000
152

    
153
#define MALLOC_ALIGN      16
154
#define BLOCK_HEADER_SIZE 16
155

    
156
typedef struct MemoryBlock {
157
    struct MemoryBlock *next;
158
    unsigned long size; /* size of block, including header */
159
} MemoryBlock;
160

    
161
static MemoryBlock *first_free_block;
162
static unsigned long malloc_addr = MALLOC_BASE;
163

    
164
static void *malloc_get_space(size_t size)
165
{
166
    void *ptr;
167
    size = TARGET_PAGE_ALIGN(size);
168
    ptr = mmap((void *)malloc_addr, size, 
169
               PROT_WRITE | PROT_READ, 
170
               MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
171
    if (ptr == MAP_FAILED)
172
        return NULL;
173
    malloc_addr += size;
174
    return ptr;
175
}
176

    
177
void *qemu_malloc(size_t size)
178
{
179
    MemoryBlock *mb, *mb1, **pmb;
180
    void *ptr;
181
    size_t size1, area_size;
182
    
183
    if (size == 0)
184
        return NULL;
185

    
186
    size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
187
    pmb = &first_free_block;
188
    for(;;) {
189
        mb = *pmb;
190
        if (mb == NULL)
191
            break;
192
        if (size <= mb->size)
193
            goto found;
194
        pmb = &mb->next;
195
    }
196
    /* no big enough blocks found: get new space */
197
    area_size = TARGET_PAGE_ALIGN(size);
198
    mb = malloc_get_space(area_size);
199
    if (!mb)
200
        return NULL;
201
    size1 = area_size - size;
202
    if (size1 > 0) {
203
        /* create a new free block */
204
        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
205
        mb1->next = NULL;
206
        mb1->size = size1;
207
        *pmb = mb1;
208
    }
209
    goto the_end;
210
 found:
211
    /* a free block was found: use it */
212
    size1 = mb->size - size;
213
    if (size1 > 0) {
214
        /* create a new free block */
215
        mb1 = (MemoryBlock *)((uint8_t *)mb + size);
216
        mb1->next = mb->next;
217
        mb1->size = size1;
218
        *pmb = mb1;
219
    } else {
220
        /* suppress the first block */
221
        *pmb = mb->next;
222
    }
223
 the_end:
224
    mb->size = size;
225
    mb->next = NULL;
226
    ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
227
#ifdef DEBUG_MALLOC
228
    qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
229
#endif
230
    return ptr;
231
}
232

    
233
void qemu_free(void *ptr)
234
{
235
    MemoryBlock *mb;
236

    
237
    mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
238
    mb->next = first_free_block;
239
    first_free_block = mb;
240
}
241

    
242
/****************************************************************/
243
/* virtual memory allocation */
244

    
245
unsigned long mmap_addr = PHYS_RAM_BASE;
246

    
247
void *get_mmap_addr(unsigned long size)
248
{
249
    unsigned long addr;
250
    addr = mmap_addr;
251
    mmap_addr += ((size + 4095) & ~4095) + 4096;
252
    return (void *)addr;
253
}
254

    
255
#else
256

    
257
int qemu_write(int fd, const void *buf, size_t n)
258
{
259
    int ret;
260
    ret = write(fd, buf, n);
261
    if (ret < 0)
262
        return -errno;
263
    else
264
        return ret;
265
}
266

    
267
void *get_mmap_addr(unsigned long size)
268
{
269
    return NULL;
270
}
271

    
272
void qemu_free(void *ptr)
273
{
274
    free(ptr);
275
}
276

    
277
void *qemu_malloc(size_t size)
278
{
279
    return malloc(size);
280
}
281

    
282
#endif
283

    
284
/****************************************************************/
285
/* printf support */
286

    
287
static inline int qemu_isdigit(int c)
288
{
289
    return c >= '0' && c <= '9';
290
}
291

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

    
294
/* from BSD ppp sources */
295
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
296
{
297
    int c, i, n;
298
    int width, prec, fillch;
299
    int base, len, neg;
300
    unsigned long val = 0;
301
    const char *f;
302
    char *str, *buf0;
303
    char num[32];
304
    static const char hexchars[] = "0123456789abcdef";
305

    
306
    buf0 = buf;
307
    --buflen;
308
    while (buflen > 0) {
309
        for (f = fmt; *f != '%' && *f != 0; ++f)
310
            ;
311
        if (f > fmt) {
312
            len = f - fmt;
313
            if (len > buflen)
314
                len = buflen;
315
            memcpy(buf, fmt, len);
316
            buf += len;
317
            buflen -= len;
318
            fmt = f;
319
        }
320
        if (*fmt == 0)
321
            break;
322
        c = *++fmt;
323
        width = prec = 0;
324
        fillch = ' ';
325
        if (c == '0') {
326
            fillch = '0';
327
            c = *++fmt;
328
        }
329
        if (c == '*') {
330
            width = va_arg(args, int);
331
            c = *++fmt;
332
        } else {
333
            while (qemu_isdigit(c)) {
334
                width = width * 10 + c - '0';
335
                c = *++fmt;
336
            }
337
        }
338
        if (c == '.') {
339
            c = *++fmt;
340
            if (c == '*') {
341
                prec = va_arg(args, int);
342
                c = *++fmt;
343
            } else {
344
                while (qemu_isdigit(c)) {
345
                    prec = prec * 10 + c - '0';
346
                    c = *++fmt;
347
                }
348
            }
349
        }
350
        /* modifiers */
351
        switch(c) {
352
        case 'l':
353
            c = *++fmt;
354
            break;
355
        default:
356
            break;
357
        }
358
        str = 0;
359
        base = 0;
360
        neg = 0;
361
        ++fmt;
362
        switch (c) {
363
        case 'd':
364
            i = va_arg(args, int);
365
            if (i < 0) {
366
                neg = 1;
367
                val = -i;
368
            } else
369
                val = i;
370
            base = 10;
371
            break;
372
        case 'o':
373
            val = va_arg(args, unsigned int);
374
            base = 8;
375
            break;
376
        case 'x':
377
        case 'X':
378
            val = va_arg(args, unsigned int);
379
            base = 16;
380
            break;
381
        case 'p':
382
            val = (unsigned long) va_arg(args, void *);
383
            base = 16;
384
            neg = 2;
385
            break;
386
        case 's':
387
            str = va_arg(args, char *);
388
            break;
389
        case 'c':
390
            num[0] = va_arg(args, int);
391
            num[1] = 0;
392
            str = num;
393
            break;
394
        default:
395
            *buf++ = '%';
396
            if (c != '%')
397
                --fmt;                /* so %z outputs %z etc. */
398
            --buflen;
399
            continue;
400
        }
401
        if (base != 0) {
402
            str = num + sizeof(num);
403
            *--str = 0;
404
            while (str > num + neg) {
405
                *--str = hexchars[val % base];
406
                val = val / base;
407
                if (--prec <= 0 && val == 0)
408
                    break;
409
            }
410
            switch (neg) {
411
            case 1:
412
                *--str = '-';
413
                break;
414
            case 2:
415
                *--str = 'x';
416
                *--str = '0';
417
                break;
418
            }
419
            len = num + sizeof(num) - 1 - str;
420
        } else {
421
            len = strlen(str);
422
            if (prec > 0 && len > prec)
423
                len = prec;
424
        }
425
        if (width > 0) {
426
            if (width > buflen)
427
                width = buflen;
428
            if ((n = width - len) > 0) {
429
                buflen -= n;
430
                for (; n > 0; --n)
431
                    *buf++ = fillch;
432
            }
433
        }
434
        if (len > buflen)
435
            len = buflen;
436
        memcpy(buf, str, len);
437
        buf += len;
438
        buflen -= len;
439
    }
440
    *buf = 0;
441
    return buf - buf0;
442
}
443

    
444
void qemu_vprintf(const char *fmt, va_list ap)
445
{
446
    char buf[1024];
447
    int len;
448
    
449
    len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
450
    qemu_write(1, buf, len);
451
}
452

    
453
void qemu_printf(const char *fmt, ...)
454
{
455
    va_list ap;
456
    va_start(ap, fmt);
457
    qemu_vprintf(fmt, ap);
458
    va_end(ap);
459
}
460