]> git.proxmox.com Git - qemu.git/blame - osdep.c
send correctly long key sequences on slow terminals - fixes backspace handling
[qemu.git] / osdep.c
CommitLineData
ea88812f
FB
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>
ea88812f
FB
28#include <errno.h>
29#include <unistd.h>
30
31#include "cpu.h"
6cb7ee85
PB
32#if defined(USE_KQEMU)
33#include "vl.h"
34#endif
ea88812f
FB
35
36#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
37
67b915a5
FB
38#include <sys/mman.h>
39#include <sys/ipc.h>
40
ea88812f
FB
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
d2bfb39a
FB
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
ea88812f
FB
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
57c30724
FB
257 if (!ptr)
258 return;
ea88812f
FB
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
6e4255f6
FB
279#ifdef _WIN32
280#include <windows.h>
281#elif defined(_BSD)
194884dd
FB
282#include <stdlib.h>
283#else
49b470eb 284#include <malloc.h>
194884dd 285#endif
49b470eb 286
ea88812f
FB
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
6e4255f6
FB
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
6cb7ee85
PB
327#else
328
329#if defined(USE_KQEMU)
49b470eb 330
6bae7ed8 331#include <sys/vfs.h>
49b470eb
FB
332#include <sys/mman.h>
333#include <fcntl.h>
334
6cb7ee85 335void *kqemu_vmalloc(size_t size)
49b470eb
FB
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;
6bae7ed8 342 struct statfs stfs;
49b470eb
FB
343
344 if (phys_ram_fd < 0) {
345 tmpdir = getenv("QEMU_TMPDIR");
346 if (!tmpdir)
347 tmpdir = "/dev/shm";
6bae7ed8
FB
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 }
6cb7ee85 370 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
6bae7ed8
FB
371 exit(1);
372 }
373 }
49b470eb
FB
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
6cb7ee85 412void kqemu_vfree(void *ptr)
49b470eb
FB
413{
414 /* may be useful some day, but currently we do not need to free */
415}
416
6cb7ee85 417#endif
49b470eb
FB
418
419/* alloc shared memory pages */
420void *qemu_vmalloc(size_t size)
421{
6cb7ee85
PB
422#if defined(USE_KQEMU)
423 if (kqemu_allowed)
424 return kqemu_vmalloc(size);
425#endif
49b470eb
FB
426#ifdef _BSD
427 return valloc(size);
428#else
429 return memalign(4096, size);
430#endif
431}
432
433void qemu_vfree(void *ptr)
434{
6cb7ee85
PB
435#if defined(USE_KQEMU)
436 if (kqemu_allowed)
437 kqemu_vfree(ptr);
438#endif
49b470eb
FB
439 free(ptr);
440}
441
442#endif
443
ea88812f
FB
444#endif
445
07d89866
FB
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
2571929a
FB
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
ea88812f
FB
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