]> git.proxmox.com Git - qemu.git/blob - osdep.c
ffa29fe8e4c812bba357b1f6612bb7b6886d47ee
[qemu.git] / 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