]> git.proxmox.com Git - qemu.git/blob - osdep.c
removed unused code
[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 /****************************************************************/
116 /* shmat replacement */
117
118 int 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 */
129 void *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
142 /****************************************************************/
143 /* sigaction bypassing the threads */
144
145 static 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
152 int 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
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
169 typedef struct MemoryBlock {
170 struct MemoryBlock *next;
171 unsigned long size; /* size of block, including header */
172 } MemoryBlock;
173
174 static MemoryBlock *first_free_block;
175 static unsigned long malloc_addr = MALLOC_BASE;
176
177 static 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
190 void *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
246 void qemu_free(void *ptr)
247 {
248 MemoryBlock *mb;
249
250 if (!ptr)
251 return;
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
260 unsigned long mmap_addr = PHYS_RAM_BASE;
261
262 void *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
272 #ifdef _WIN32
273 #include <windows.h>
274 #elif defined(_BSD)
275 #include <stdlib.h>
276 #else
277 #include <malloc.h>
278 #endif
279
280 void *get_mmap_addr(unsigned long size)
281 {
282 return NULL;
283 }
284
285 void qemu_free(void *ptr)
286 {
287 free(ptr);
288 }
289
290 void *qemu_malloc(size_t size)
291 {
292 return malloc(size);
293 }
294
295 #if defined(_WIN32)
296
297 void *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
305 void qemu_vfree(void *ptr)
306 {
307 VirtualFree(ptr, 0, MEM_RELEASE);
308 }
309
310 #else
311
312 #if defined(USE_KQEMU)
313
314 #include <sys/vfs.h>
315 #include <sys/mman.h>
316 #include <fcntl.h>
317
318 void *kqemu_vmalloc(size_t size)
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;
325 struct statfs stfs;
326
327 if (phys_ram_fd < 0) {
328 tmpdir = getenv("QEMU_TMPDIR");
329 if (!tmpdir)
330 tmpdir = "/dev/shm";
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 }
353 fprintf(stderr, "Or disable the accelerator module with -no-kqemu\n");
354 exit(1);
355 }
356 }
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
395 void kqemu_vfree(void *ptr)
396 {
397 /* may be useful some day, but currently we do not need to free */
398 }
399
400 #endif
401
402 /* alloc shared memory pages */
403 void *qemu_vmalloc(size_t size)
404 {
405 #if defined(USE_KQEMU)
406 if (kqemu_allowed)
407 return kqemu_vmalloc(size);
408 #endif
409 #ifdef _BSD
410 return valloc(size);
411 #else
412 return memalign(4096, size);
413 #endif
414 }
415
416 void qemu_vfree(void *ptr)
417 {
418 #if defined(USE_KQEMU)
419 if (kqemu_allowed)
420 kqemu_vfree(ptr);
421 #endif
422 free(ptr);
423 }
424
425 #endif
426
427 #endif
428
429 void *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
439 char *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 }