]> git.proxmox.com Git - mirror_qemu.git/blame - osdep.c
async file I/O API
[mirror_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
ea88812f
FB
115/****************************************************************/
116/* shmat replacement */
117
118int qemu_ipc(int call, unsigned long first,
119 unsigned long second, unsigned long third,
120 void *ptr, unsigned long fifth)
121{
122 QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
123}
124
125#define SHMAT 21
126
127/* we must define shmat so that a specific address will be used when
128 mapping the X11 ximage */
129void *shmat(int shmid, const void *shmaddr, int shmflg)
130{
131 void *ptr;
132 int ret;
133 /* we give an address in the right memory area */
134 if (!shmaddr)
135 shmaddr = get_mmap_addr(8192 * 1024);
136 ret = qemu_ipc(SHMAT, shmid, shmflg, (unsigned long)&ptr, (void *)shmaddr, 0);
137 if (ret < 0)
138 return NULL;
139 return ptr;
140}
141
d2bfb39a
FB
142/****************************************************************/
143/* sigaction bypassing the threads */
144
145static int kernel_sigaction(int signum, const struct qemu_sigaction *act,
146 struct qemu_sigaction *oldact,
147 int sigsetsize)
148{
149 QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
150}
151
152int qemu_sigaction(int signum, const struct qemu_sigaction *act,
153 struct qemu_sigaction *oldact)
154{
155 return kernel_sigaction(signum, act, oldact, 8);
156}
157
ea88812f
FB
158/****************************************************************/
159/* memory allocation */
160
161//#define DEBUG_MALLOC
162
163#define MALLOC_BASE 0xab000000
164#define PHYS_RAM_BASE 0xac000000
165
166#define MALLOC_ALIGN 16
167#define BLOCK_HEADER_SIZE 16
168
169typedef struct MemoryBlock {
170 struct MemoryBlock *next;
171 unsigned long size; /* size of block, including header */
172} MemoryBlock;
173
174static MemoryBlock *first_free_block;
175static unsigned long malloc_addr = MALLOC_BASE;
176
177static void *malloc_get_space(size_t size)
178{
179 void *ptr;
180 size = TARGET_PAGE_ALIGN(size);
181 ptr = mmap((void *)malloc_addr, size,
182 PROT_WRITE | PROT_READ,
183 MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
184 if (ptr == MAP_FAILED)
185 return NULL;
186 malloc_addr += size;
187 return ptr;
188}
189
190void *qemu_malloc(size_t size)
191{
192 MemoryBlock *mb, *mb1, **pmb;
193 void *ptr;
194 size_t size1, area_size;
195
196 if (size == 0)
197 return NULL;
198
199 size = (size + BLOCK_HEADER_SIZE + MALLOC_ALIGN - 1) & ~(MALLOC_ALIGN - 1);
200 pmb = &first_free_block;
201 for(;;) {
202 mb = *pmb;
203 if (mb == NULL)
204 break;
205 if (size <= mb->size)
206 goto found;
207 pmb = &mb->next;
208 }
209 /* no big enough blocks found: get new space */
210 area_size = TARGET_PAGE_ALIGN(size);
211 mb = malloc_get_space(area_size);
212 if (!mb)
213 return NULL;
214 size1 = area_size - size;
215 if (size1 > 0) {
216 /* create a new free block */
217 mb1 = (MemoryBlock *)((uint8_t *)mb + size);
218 mb1->next = NULL;
219 mb1->size = size1;
220 *pmb = mb1;
221 }
222 goto the_end;
223 found:
224 /* a free block was found: use it */
225 size1 = mb->size - size;
226 if (size1 > 0) {
227 /* create a new free block */
228 mb1 = (MemoryBlock *)((uint8_t *)mb + size);
229 mb1->next = mb->next;
230 mb1->size = size1;
231 *pmb = mb1;
232 } else {
233 /* suppress the first block */
234 *pmb = mb->next;
235 }
236 the_end:
237 mb->size = size;
238 mb->next = NULL;
239 ptr = ((uint8_t *)mb + BLOCK_HEADER_SIZE);
240#ifdef DEBUG_MALLOC
241 qemu_printf("malloc: size=0x%x ptr=0x%lx\n", size, (unsigned long)ptr);
242#endif
243 return ptr;
244}
245
246void qemu_free(void *ptr)
247{
248 MemoryBlock *mb;
249
57c30724
FB
250 if (!ptr)
251 return;
ea88812f
FB
252 mb = (MemoryBlock *)((uint8_t *)ptr - BLOCK_HEADER_SIZE);
253 mb->next = first_free_block;
254 first_free_block = mb;
255}
256
257/****************************************************************/
258/* virtual memory allocation */
259
260unsigned long mmap_addr = PHYS_RAM_BASE;
261
262void *get_mmap_addr(unsigned long size)
263{
264 unsigned long addr;
265 addr = mmap_addr;
266 mmap_addr += ((size + 4095) & ~4095) + 4096;
267 return (void *)addr;
268}
269
270#else
271
6e4255f6
FB
272#ifdef _WIN32
273#include <windows.h>
274#elif defined(_BSD)
194884dd
FB
275#include <stdlib.h>
276#else
49b470eb 277#include <malloc.h>
194884dd 278#endif
49b470eb 279
ea88812f
FB
280void *get_mmap_addr(unsigned long size)
281{
282 return NULL;
283}
284
285void qemu_free(void *ptr)
286{
287 free(ptr);
288}
289
290void *qemu_malloc(size_t size)
291{
292 return malloc(size);
293}
294
6e4255f6
FB
295#if defined(_WIN32)
296
297void *qemu_vmalloc(size_t size)
298{
299 /* FIXME: this is not exactly optimal solution since VirtualAlloc
300 has 64Kb granularity, but at least it guarantees us that the
301 memory is page aligned. */
302 return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
303}
304
305void qemu_vfree(void *ptr)
306{
307 VirtualFree(ptr, 0, MEM_RELEASE);
308}
309
6cb7ee85
PB
310#else
311
312#if defined(USE_KQEMU)
49b470eb 313
6bae7ed8 314#include <sys/vfs.h>
49b470eb
FB
315#include <sys/mman.h>
316#include <fcntl.h>
317
6cb7ee85 318void *kqemu_vmalloc(size_t size)
49b470eb
FB
319{
320 static int phys_ram_fd = -1;
321 static int phys_ram_size = 0;
322 const char *tmpdir;
323 char phys_ram_file[1024];
324 void *ptr;
6bae7ed8 325 struct statfs stfs;
49b470eb
FB
326
327 if (phys_ram_fd < 0) {
328 tmpdir = getenv("QEMU_TMPDIR");
329 if (!tmpdir)
330 tmpdir = "/dev/shm";
6bae7ed8
FB
331 if (statfs(tmpdir, &stfs) == 0) {
332 int64_t free_space;
333 int ram_mb;
334
335 extern int ram_size;
336 free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
337 if ((ram_size + 8192 * 1024) >= free_space) {
338 ram_mb = (ram_size / (1024 * 1024));
339 fprintf(stderr,
340 "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
341 tmpdir, ram_mb);
342 if (strcmp(tmpdir, "/dev/shm") == 0) {
343 fprintf(stderr, "To have more space available provided you have enough RAM and swap, do as root:\n"
344 "umount /dev/shm\n"
345 "mount -t tmpfs -o size=%dm none /dev/shm\n",
346 ram_mb + 16);
347 } else {
348 fprintf(stderr,
349 "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
350 "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
351 "temporary RAM file will be opened.\n");
352 }
6cb7ee85 353 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
6bae7ed8
FB
354 exit(1);
355 }
356 }
49b470eb
FB
357 snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
358 tmpdir);
359 if (mkstemp(phys_ram_file) < 0) {
360 fprintf(stderr,
361 "warning: could not create temporary file in '%s'.\n"
362 "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
363 "Using '/tmp' as fallback.\n",
364 tmpdir);
365 snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
366 "/tmp");
367 if (mkstemp(phys_ram_file) < 0) {
368 fprintf(stderr, "Could not create temporary memory file '%s'\n",
369 phys_ram_file);
370 exit(1);
371 }
372 }
373 phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
374 if (phys_ram_fd < 0) {
375 fprintf(stderr, "Could not open temporary memory file '%s'\n",
376 phys_ram_file);
377 exit(1);
378 }
379 unlink(phys_ram_file);
380 }
381 size = (size + 4095) & ~4095;
382 ftruncate(phys_ram_fd, phys_ram_size + size);
383 ptr = mmap(NULL,
384 size,
385 PROT_WRITE | PROT_READ, MAP_SHARED,
386 phys_ram_fd, phys_ram_size);
387 if (ptr == MAP_FAILED) {
388 fprintf(stderr, "Could not map physical memory\n");
389 exit(1);
390 }
391 phys_ram_size += size;
392 return ptr;
393}
394
6cb7ee85 395void kqemu_vfree(void *ptr)
49b470eb
FB
396{
397 /* may be useful some day, but currently we do not need to free */
398}
399
6cb7ee85 400#endif
49b470eb
FB
401
402/* alloc shared memory pages */
403void *qemu_vmalloc(size_t size)
404{
6cb7ee85
PB
405#if defined(USE_KQEMU)
406 if (kqemu_allowed)
407 return kqemu_vmalloc(size);
408#endif
49b470eb
FB
409#ifdef _BSD
410 return valloc(size);
411#else
412 return memalign(4096, size);
413#endif
414}
415
416void qemu_vfree(void *ptr)
417{
6cb7ee85
PB
418#if defined(USE_KQEMU)
419 if (kqemu_allowed)
420 kqemu_vfree(ptr);
421#endif
49b470eb
FB
422 free(ptr);
423}
424
425#endif
426
ea88812f
FB
427#endif
428
07d89866
FB
429void *qemu_mallocz(size_t size)
430{
431 void *ptr;
432 ptr = qemu_malloc(size);
433 if (!ptr)
434 return NULL;
435 memset(ptr, 0, size);
436 return ptr;
437}
438
2571929a
FB
439char *qemu_strdup(const char *str)
440{
441 char *ptr;
442 ptr = qemu_malloc(strlen(str) + 1);
443 if (!ptr)
444 return NULL;
445 strcpy(ptr, str);
446 return ptr;
447}