Statistics
| Branch: | Revision:

root / osdep.c @ 3e11db9a

History | View | Annotate | Download (10.4 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
/* memory allocation */
148

    
149
//#define DEBUG_MALLOC
150

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

    
154
#define MALLOC_ALIGN      16
155
#define BLOCK_HEADER_SIZE 16
156

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

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

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

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

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

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

    
238
    if (!ptr)
239
        return;
240
    mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
241
    mb->next = first_free_block;
242
    first_free_block = mb;
243
}
244

    
245
/****************************************************************/
246
/* virtual memory allocation */
247

    
248
unsigned long mmap_addr = PHYS_RAM_BASE;
249

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

    
258
#else
259

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

    
270
void *get_mmap_addr(unsigned long size)
271
{
272
    return NULL;
273
}
274

    
275
void qemu_free(void *ptr)
276
{
277
    free(ptr);
278
}
279

    
280
void *qemu_malloc(size_t size)
281
{
282
    return malloc(size);
283
}
284

    
285
#endif
286

    
287
void *qemu_mallocz(size_t size)
288
{
289
    void *ptr;
290
    ptr = qemu_malloc(size);
291
    if (!ptr)
292
        return NULL;
293
    memset(ptr, 0, size);
294
    return ptr;
295
}
296

    
297
char *qemu_strdup(const char *str)
298
{
299
    char *ptr;
300
    ptr = qemu_malloc(strlen(str) + 1);
301
    if (!ptr)
302
        return NULL;
303
    strcpy(ptr, str);
304
    return ptr;
305
}
306

    
307
/****************************************************************/
308
/* printf support */
309

    
310
static inline int qemu_isdigit(int c)
311
{
312
    return c >= '0' && c <= '9';
313
}
314

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

    
317
/* from BSD ppp sources */
318
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
319
{
320
    int c, i, n;
321
    int width, prec, fillch;
322
    int base, len, neg;
323
    unsigned long val = 0;
324
    const char *f;
325
    char *str, *buf0;
326
    char num[32];
327
    static const char hexchars[] = "0123456789abcdef";
328

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

    
467
void qemu_vprintf(const char *fmt, va_list ap)
468
{
469
    char buf[1024];
470
    int len;
471
    
472
    len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
473
    qemu_write(1, buf, len);
474
}
475

    
476
void qemu_printf(const char *fmt, ...)
477
{
478
    va_list ap;
479
    va_start(ap, fmt);
480
    qemu_vprintf(fmt, ap);
481
    va_end(ap);
482
}
483