Fix partial transfer bug.
[qemu/mini2440.git] / osdep.c
blobffa29fe8e4c812bba357b1f6612bb7b6886d47ee
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
31 #include "cpu.h"
32 #if defined(USE_KQEMU)
33 #include "vl.h"
34 #endif
36 #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(CONFIG_USER_ONLY)
38 #include <sys/mman.h>
39 #include <sys/ipc.h>
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 */
45 #include <linux/unistd.h>
47 #define QEMU_SYSCALL0(name) \
48 { \
49 long __res; \
50 __asm__ volatile ("int $0x80" \
51 : "=a" (__res) \
52 : "0" (__NR_##name)); \
53 return __res; \
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; \
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; \
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; \
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; \
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; \
104 #define QEMU_SYSCALL6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
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; \
115 int qemu_write(int fd, const void *buf, size_t n)
117 QEMU_SYSCALL3(write, fd, buf, n);
122 /****************************************************************/
123 /* shmat replacement */
125 int qemu_ipc(int call, unsigned long first,
126 unsigned long second, unsigned long third,
127 void *ptr, unsigned long fifth)
129 QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
132 #define SHMAT 21
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)
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;
149 /****************************************************************/
150 /* sigaction bypassing the threads */
152 static int kernel_sigaction(int signum, const struct qemu_sigaction *act,
153 struct qemu_sigaction *oldact,
154 int sigsetsize)
156 QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
159 int qemu_sigaction(int signum, const struct qemu_sigaction *act,
160 struct qemu_sigaction *oldact)
162 return kernel_sigaction(signum, act, oldact, 8);
165 /****************************************************************/
166 /* memory allocation */
168 //#define DEBUG_MALLOC
170 #define MALLOC_BASE 0xab000000
171 #define PHYS_RAM_BASE 0xac000000
173 #define MALLOC_ALIGN 16
174 #define BLOCK_HEADER_SIZE 16
176 typedef struct MemoryBlock {
177 struct MemoryBlock *next;
178 unsigned long size; /* size of block, including header */
179 } MemoryBlock;
181 static MemoryBlock *first_free_block;
182 static unsigned long malloc_addr = MALLOC_BASE;
184 static void *malloc_get_space(size_t size)
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;
197 void *qemu_malloc(size_t size)
199 MemoryBlock *mb, *mb1, **pmb;
200 void *ptr;
201 size_t size1, area_size;
203 if (size == 0)
204 return NULL;
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;
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;
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;
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;
253 void qemu_free(void *ptr)
255 MemoryBlock *mb;
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;
264 /****************************************************************/
265 /* virtual memory allocation */
267 unsigned long mmap_addr = PHYS_RAM_BASE;
269 void *get_mmap_addr(unsigned long size)
271 unsigned long addr;
272 addr = mmap_addr;
273 mmap_addr += ((size + 4095) & ~4095) + 4096;
274 return (void *)addr;
277 #else
279 #ifdef _WIN32
280 #include <windows.h>
281 #elif defined(_BSD)
282 #include <stdlib.h>
283 #else
284 #include <malloc.h>
285 #endif
287 int qemu_write(int fd, const void *buf, size_t n)
289 int ret;
290 ret = write(fd, buf, n);
291 if (ret < 0)
292 return -errno;
293 else
294 return ret;
297 void *get_mmap_addr(unsigned long size)
299 return NULL;
302 void qemu_free(void *ptr)
304 free(ptr);
307 void *qemu_malloc(size_t size)
309 return malloc(size);
312 #if defined(_WIN32)
314 void *qemu_vmalloc(size_t size)
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);
322 void qemu_vfree(void *ptr)
324 VirtualFree(ptr, 0, MEM_RELEASE);
327 #else
329 #if defined(USE_KQEMU)
331 #include <sys/vfs.h>
332 #include <sys/mman.h>
333 #include <fcntl.h>
335 void *kqemu_vmalloc(size_t size)
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;
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;
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");
370 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
371 exit(1);
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);
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);
396 unlink(phys_ram_file);
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);
408 phys_ram_size += size;
409 return ptr;
412 void kqemu_vfree(void *ptr)
414 /* may be useful some day, but currently we do not need to free */
417 #endif
419 /* alloc shared memory pages */
420 void *qemu_vmalloc(size_t size)
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
433 void qemu_vfree(void *ptr)
435 #if defined(USE_KQEMU)
436 if (kqemu_allowed)
437 kqemu_vfree(ptr);
438 #endif
439 free(ptr);
442 #endif
444 #endif
446 void *qemu_mallocz(size_t size)
448 void *ptr;
449 ptr = qemu_malloc(size);
450 if (!ptr)
451 return NULL;
452 memset(ptr, 0, size);
453 return ptr;
456 char *qemu_strdup(const char *str)
458 char *ptr;
459 ptr = qemu_malloc(strlen(str) + 1);
460 if (!ptr)
461 return NULL;
462 strcpy(ptr, str);
463 return ptr;
466 /****************************************************************/
467 /* printf support */
469 static inline int qemu_isdigit(int c)
471 return c >= '0' && c <= '9';
474 #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
476 /* from BSD ppp sources */
477 int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args)
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";
488 buf0 = buf;
489 --buflen;
490 while (buflen > 0) {
491 for (f = fmt; *f != '%' && *f != 0; ++f)
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;
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;
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;
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;
532 /* modifiers */
533 switch(c) {
534 case 'l':
535 c = *++fmt;
536 break;
537 default:
538 break;
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;
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;
592 switch (neg) {
593 case 1:
594 *--str = '-';
595 break;
596 case 2:
597 *--str = 'x';
598 *--str = '0';
599 break;
601 len = num + sizeof(num) - 1 - str;
602 } else {
603 len = strlen(str);
604 if (prec > 0 && len > prec)
605 len = prec;
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;
616 if (len > buflen)
617 len = buflen;
618 memcpy(buf, str, len);
619 buf += len;
620 buflen -= len;
622 *buf = 0;
623 return buf - buf0;
626 void qemu_vprintf(const char *fmt, va_list ap)
628 char buf[1024];
629 int len;
631 len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
632 qemu_write(1, buf, len);
635 void qemu_printf(const char *fmt, ...)
637 va_list ap;
638 va_start(ap, fmt);
639 qemu_vprintf(fmt, ap);
640 va_end(ap);