ffa29fe8e4c812bba357b1f6612bb7b6886d47ee
[qemu] / osdep.c
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 { \
49 long __res; \
50 __asm__ volatile ("int $0x80" \
51         : "=a" (__res) \
52         : "0" (__NR_##name)); \
53 return __res; \
54 }
55
56 #define QEMU_SYSCALL1(name,arg1) \
57 { \
58 long __res; \
59 __asm__ volatile ("int $0x80" \
60         : "=a" (__res) \
61         : "0" (__NR_##name),"b" ((long)(arg1))); \
62 return __res; \
63 }
64
65 #define QEMU_SYSCALL2(name,arg1,arg2) \
66 { \
67 long __res; \
68 __asm__ volatile ("int $0x80" \
69         : "=a" (__res) \
70         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
71 return __res; \
72 }
73
74 #define QEMU_SYSCALL3(name,arg1,arg2,arg3) \
75 { \
76 long __res; \
77 __asm__ volatile ("int $0x80" \
78         : "=a" (__res) \
79         : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
80                   "d" ((long)(arg3))); \
81 return __res; \
82 }
83
84 #define QEMU_SYSCALL4(name,arg1,arg2,arg3,arg4) \
85 { \
86 long __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))); \
91 return __res; \
92
93
94 #define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
95 { \
96 long __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))); \
101 return __res; \
102 }
103
104 #define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
105 { \
106 long __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))); \
112 return __res; \
113 }
114
115 int 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
125 int 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 */
136 void *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
152 static 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
159 int 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
176 typedef struct MemoryBlock {
177     struct MemoryBlock *next;
178     unsigned long size; /* size of block, including header */
179 } MemoryBlock;
180
181 static MemoryBlock *first_free_block;
182 static unsigned long malloc_addr = MALLOC_BASE;
183
184 static 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
197 void *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
253 void 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
267 unsigned long mmap_addr = PHYS_RAM_BASE;
268
269 void *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
287 int 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
297 void *get_mmap_addr(unsigned long size)
298 {
299     return NULL;
300 }
301
302 void qemu_free(void *ptr)
303 {
304     free(ptr);
305 }
306
307 void *qemu_malloc(size_t size)
308 {
309     return malloc(size);
310 }
311
312 #if defined(_WIN32)
313
314 void *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
322 void 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
335 void *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
412 void 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 */
420 void *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
433 void 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
446 void *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
456 char *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
469 static 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 */
477 int 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
626 void 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
635 void 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